iOS開發tips-PhotoKit

来源:https://www.cnblogs.com/kenshincui/archive/2019/11/17/ios-kai-fatipsphotokit.html
-Advertisement-
Play Games

概述PhotoKit應該是iOS 8 開始引入為了替代之前ALAssetsLibrary的相冊資源訪問的標準庫,後者在iOS 9開始被棄用。當然相對於ALAssetsLibrary其擴展性更高,api使用起來也更加的強大,但這並非今天討論的重點,這裡主要討論PhotoKit使用的一些技巧和容易踩的坑... ...


概述

PhotoKit應該是iOS 8 開始引入為了替代之前ALAssetsLibrary的相冊資源訪問的標準庫,後者在iOS 9開始被棄用。當然相對於ALAssetsLibrary其擴展性更高,api使用起來也更加的強大,但這並非今天討論的重點,這裡主要討論PhotoKit使用的一些技巧和容易踩的坑。

PHImageManager or Custom

訪問相冊資源常用的操作還是獲取資源,比如獲取一張相冊的圖片,可以通過PHImageManager.default().requestImage(xxx)一個回調就可以了,其實除了簡單的圖片拉取蘋果建議大家使用一個自己維護的PHCachingImageManager(PHImageManager子類)單例,因為從名字可以看出它可以進行資源緩存(具體用法參見:PHCachingImageManager),這個在列表滑動過程中比較有用,因為可以使用startCachingImages(for:targetSize:contentMode:options:)預載入還未顯示的資源,在不需要使用的時候調用stopCachingImages(for:targetSize:contentMode:options:)移除緩存,除此之外其實它更多的是使用父類的功能。

關於requestImage(for:targetSize:contentMode:options:resultHandler:)方法其實它的options是更容易讓大家使用的時候經常迷糊的地方,因為iOS相冊的照片很可能並不在本地而是在iCloud上面存儲,本地只有縮略圖:

  • isNetworkAccessAllowed:是不是打開網路載入,對於iCloud優化的圖片本地只有縮略圖,需要了開啟網路載入,預設是false,但是建議非特殊情況下不要關閉網路載入設為true
  • isSynchronous:獲取圖片時是否同步獲取,否則非同步獲取,非特殊情況下不建議使用同步獲取會阻塞線程,預設為false
  • version:使用資源的版本,例如說一個視頻獲取過程中是要獲取編輯過的還是獲取原始視頻(因為iOS的相冊編輯時可以恢復的,所以其實裡面包含了編輯信息),預設current對於未編輯的則獲取原始資源,編輯過則獲取編輯過的資源。
  • deliveryMode:字面意思資源交付模式,就是當發起一個請求後系統如何提供請求的資源(不過很可能這個資源並不在本地),預設是opportunistic同步調用只返回一種資源非同步調用返回多種資源(例如不同尺寸的圖片,這也就是說和上面的isSynchronous相關);highQualityFormat任何情況下只返回高質量的一種資源;fastFormat任何情況下只返回一種結果,它可能是低清圖片(是不是低清晰度可以通過resultHandler結果中的info欄位PHImageResultIsDegradedKey來判斷是不是低清晰度)。
  • resizeMode:重設尺寸模式,這個其實關係到方法中targetSize參數,預設是fast代表當本地是原圖則返回原圖,本地是縮略圖則使用targetSize來獲取一個最優圖片,但是尺寸可能比targetSize要略大(註意如果targetSize是PHImageManagerMaximumSize則會拉取原圖此屬性此時沒有意義直接忽略);none則返回原圖大小;exactfast但是返回的高清圖。但是在非同步情況下因為可能存在兩種圖片會稍有不同,下麵分兩種情況介紹。

isSynchronousdeliveryModeresizeMode之間的關係(前提是開啟網路載入isNetworkAccessAllowed = true):

isSynchronous = true同步載入:此時deliveryMode會被忽略掉,所以只要看resizeMode

  • none:返回原圖尺寸
  • fast:原圖為縮略圖時使用targetSize優化,返回一個可能比targetSize稍大的圖片
  • exact:返回指定targetSize的高清圖片

isSynchronous = false非同步載入:此時要看deliveryMode和resizeMode兩者的變化情況

  • deliveryMode = opportunistic

    • none:先返回低清圖片,再返回原圖
    • fast:先返回低清圖片,再返回使用targetSize優化,可能比targetSize稍大的圖片
    • exact:先返回低清圖片,再返回指定targetSize的高清圖片
  • deliveryMode = highQualityFormat

    • none:返回原圖
    • fast:返回使用targetSize優化,可能比targetSize稍大的圖片
    • exact:返回指定targetSize的高清圖片
  • deliveryMode = fastFormat

    • none:返回低清圖片
    • fast:返回低清圖片
    • exact:返回低清圖片

對於是否返回兩次結果總結起來對於返回結果只有非同步請求在不設置deliveryMode或者deliveryMode = opportunistic 時會發送兩次請求。

沒錯上面的情況如果瞭解不清楚很容易掉進坑裡,一般的情況下只要打開網路,使用預設值即可。但是話說沒有網路的情況下是什麼情況呢?

無網路情況

上面說了那麼多配置那麼對於沒有網路的情況呢?因為PHImageRequestOptions預設其實就是沒有網路的。先看一下下麵的請求:

let requestOption = PHImageRequestOptions()
requestOption.resizeMode = .exact
let scale:CGFloat = UIScreen.main.scale
let newSize = CGSize(width: 200.0, height: 200)
PHImageManager.default().requestImage(for: asset, targetSize: newSize, contentMode: .aspectFill, options: requestOption,resultHandler: completeHandler)

首先沒有設置isNetworkAccessAllowed屬性,那麼預設值就是false,這個時候也就是沒有任何網路請求,其次resizeMode = .exact也就是請求比較高清的圖片。但是一個重要的問題是這個圖片可能會是一個低清圖片,甚至達不到一個200200的縮略圖的預期,有可能特別模糊。
按照前面說的,deliveryMode 沒有設置預設是
opportunisticisSynchronous*沒有設置預設是false,在非同步情況下是 首先這種情況下也會返回兩個結果,列印info信息:
第一次:
[AnyHashable("PHImageResultIsDegradedKey"): 1, AnyHashable("PHImageResultRequestIDKey"): 1100]
第二次:
[AnyHashable("PHImageResultIsDegradedKey"): 0, AnyHashable("PHImageErrorKey"): Error Domain=NSCocoaErrorDomain Code=-1 "(null)", AnyHashable("PHImageResultIsInCloudKey"): 1, AnyHashable("PHImageResultRequestIDKey"): 1100]

可以看出第一次是低清圖片,第二次是高清,但是此時出錯了PHImageResultIsInCloudKey = 1,本地並沒有高清圖,但是因為無法訪問網路去獲取就報錯了,拋出PHImageErrorKey信息,同時此時返回的image = nil,這樣的結果就是只能看到低清圖片。因此是否返回清晰照片除了上面說的,還和是否允許網路請求有直接關係。

綜上來看除非特殊情況下,請打開網路請求使用非同步請求,並且在合適的時機判斷是否請求返回兩次。

視頻獲取

對於視頻資源的獲取和圖片還有些不同,因為使用PhotoKit上傳視頻的過程並不是直接獲取到視頻路徑來做的,當然如果不熟悉這個過程很可能使用下麵的方式:

let option = PHVideoRequestOptions()
option.isNetworkAccessAllowed = true
option.version = .current
option.deliveryMode = .highQualityFormat
PHImageManager.default().requestAVAsset(forVideo: phAsset, options: option) { (avAsset, _, _) in
    if let avAsset = avAsset as? AVURLAsset {
        let fileURL = avAsset.url
        // upload by fileURL
    }
}

這套代碼遇到的問題很可能是iOS 10之前的系統上傳失敗,之後的基本還是可以傳成功的,主要是因為這個url路徑在低版本系統訪問受限。

正確的姿勢應該是先把視頻導出到沙盒然後從本地上傳,那麼如何copy到本地呢?答案是使用PHAssetResourceManager,這個類出現的比較晚在iOS 9才引入的,就是為了方便資源管理,可以通過他將本地相冊的資源寫入沙盒然後上傳沙盒的資源。

let resources = PHAssetResource.assetResources(for: phAsset)
let options = PHAssetResourceRequestOptions()
options.isNetworkAccessAllowed = true
PHAssetResourceManager.default().writeData(for: assetResource, toFile: videoURL, options: options, completionHandler: { (error) in
    // upload by videoURL
    
})

但是這並非就萬事大吉了,接下來的一個bug就是,通過這種方式如果上傳用戶已經編輯過的資源會發現它上傳的是編輯之前的(比如說用戶將60s的視頻通過系統相冊剪輯到50s,它上傳的還是60s的),因為它相比較於PHImageManager請求可以設置PHVideoRequestOptions.version它缺少了這個信息,查找api也沒有發現可以用的設置,所以這種方式還是不可取(如果有朋友知道怎麼使用這種方式獲取不同的version可以留言告訴我)。所以這時可以採用PHImageManager的另一個方法requestExportSession(xxx)將視頻導出到沙盒然後上傳,但是這麼做的另一個小問題就是如果想要導出原始視頻就不太可能了,只能儘可能拿到一個更高清晰度的視頻。

let videoOption = PHVideoRequestOptions()
videoOption.version = PHVideoRequestOptionsVersion.current
videoOption.isNetworkAccessAllowed = true
PHImageManager.default().requestExportSession(forVideo: phAsset, options: videoOption, exportPreset: AVAssetExportPresetHighestQuality) { (exportSession, info) in
    if let exportSession = exportSession {
        exportSession.outputURL = videoURL
        exportSession.outputFileType = AVFileType.mp4
        exportSession.exportAsynchronously {
        if exportSession.status == AVAssetExportSession.Status.completed {
            // upload by videoURL
        }
    }
}

話說到了這裡是不是就真的沒事了?試著用下麵的視頻上傳試試:
TestVideo.zip
exportSession.status應該會失敗,當然如果你是iOS 13應該是可以的,但是如果是iOS 13以下在當前環境測試都是通不過的,這個視頻查看meta信息也沒有什麼特殊的,但是這個是Android導出的一個視頻,失敗信息是:無法完成此操作。除此之外並沒有有用的信息,初步猜測導出時應該是編解碼出錯了。

其實到了這裡,用上面的方式應該就無法解決這個問題了,至少目前沒有找到有效的辦法,兜底策略就是失敗後採用上面的第二種方式。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 原文地址 https://sspai.com/post/35225 讓我們從實際需求出發,看看問題出在哪裡,併在此基礎上認識和學習使用 Hazel。 電腦隨著使用時間的增長,其中的文件也在瘋狂的增長,時間長了也就會出現各種混亂:大量文件堆放在一起,舊文件很少清理,分不清哪些文件還有用,找不到需要的文 ...
  • 表結構修改(alter) 查看表的結構:desc 表名; 修改表名:alter table 表名 rename to 新表名; 修改欄位名:alter table 表名 change 舊欄位名 新欄位名 數據類型; 修改欄位類型:alter table 表名 modify 欄位名 數據類型; 添加字 ...
  • 雅虎日本是一家雅虎和軟銀合資的日本互聯網公司,是日本最受歡迎的門戶網站之一。雅虎日本的互聯網服務在日本市場占主導地位。 下圖從三個維度顯示了雅虎日本的經營規模。第一個是服務數量,雅虎日本提供上百種互聯網服務;第二個是伺服器數量,雅虎日本使用超過 150,000 台伺服器(大多為裸機伺服器)全天候支持 ...
  • 轉載自:https://www.cnblogs.com/swtool/p/8202965.html ...
  • sqlite中只支持 ALTER TABLE 命令的 RENAME TABLE 和 ADD COLUMN。 其他類型的 ALTER TABLE 操作如 DROP COLUMN,ALTER COLUMN,ADD CONSTRAINT 等等均被忽略。 重命名錶名: alter table tableNa ...
  • 篩選條件 比較運算符 等於: = ( 註意!不是 == ) 不等於: != 或 大於: 大於等於: = 小於: 聚合分組 常用聚合函數 統計個數:COUNT(column) 最大值:MAX(column) 最小值:MIN(column) 求和:SUM(column) 平均值:AVG(column) ...
  • 2019年11月08日 數磚的 Xingbo Jiang 大佬給社區發了一封郵件,宣佈 Apache Spark 3.0 預覽版正式發佈,這個版本主要是為了對即將發佈的 Apache Spark 3.0 版本進行大規模社區測試。無論是從 API 還是從功能上來說,這個預覽版都不是一個穩定的版本,它的 ...
  • 公眾號回覆 獲取安裝包 項目地址: "Wanandroid Compose" 經過前段時間的 Android Dev Summit ,相信你已經大概瞭解了 Jetpack Compose 。如果你還沒有聽說過,可以閱讀這篇文章 "Jetpack Compose 最新進展" 。總而言之,Compose ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...