<h2>一、概況</h2>
PhotoKit 基本構(gòu)成的介紹:
- PHAsset:代表照片庫中的一個資源,跟 ALAsset 類似, 通過 PHAsset 可以獲取和保存資源
- PHFetchOptions:獲取資源的參數(shù),可以nil,及使用系統(tǒng)默認值
- PHAssetCollection:PHCollection 的子類,表示一個相冊或者一個時刻,后者是一個只能相冊(系統(tǒng)提供的特定的一系列相冊,例如:最近刪除,視頻列表, 收藏等等)
- PHFetchResult:表示一系列的資源的結(jié)果集合,也可以是相冊的集合,從PHCollection 的類方法中獲得
- PHImageManager:用于處理資源的加載,加載圖片的過程帶有緩存處理,可以通過傳入一個 PHImageRequestOptions:如上面所說,控制加載圖片時的一系列參數(shù)
這里還有一個額外的概念PHCollectionList,表示一組PHCollection,它本身也是一個PHCollection,因此 PHCollection 作為一個集合,可以包含其他集合,這使得 PhotoKit 的組成比 ALAssetLibrary 要復(fù)雜一些。另外與 ALAssetLibrary 相似,一個 PHAsset 可以同時屬于多個不同的 PHAssetCollection,最常見的例子就是剛剛拍攝的照片,至少同時屬于“最近添加”、“相機膠卷”已經(jīng)“照片-精選”這三個 PHAssetCollection。
<h2>二、PhotoKit 的機制</h2>
1、獲取資源
在 ALAssetLibrary 中獲取數(shù)據(jù),無論是相冊,還是資源,本質(zhì)上都是使用枚舉的方式,遍歷照片庫取得相應(yīng)的數(shù)據(jù),并且數(shù)據(jù)是從 ALAssetLibrary(照片庫)- ALAssetGroup(相冊)- ALAsset(資源)這一路徑逐層獲取,這樣好處很明顯,就是非常符合實際應(yīng)用中資源的顯示路徑:照片庫 - 相冊 - 圖片或視頻,但由于枚舉的方式獲取資源,效率低而且不靈活。
而在 PhotoKit 中,則是采用“獲取”的方式拉取資源,這些獲取的手段,都是一系列形如 class func fetchXXX(,Options:PHFetchOptions)-> PHFetchResult 的類方法,具體使用那個類方法,則會根據(jù)獲取的是相冊、時刻還是資源,這類方法中的 option 充當了過濾器的作用,可以過來相冊的類型,日期,名稱等,從而獲取對于的資源而不需要枚舉。例如在前文中累加個的幾個小例子:
// 列出所有相冊智能相冊
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
// 列出所有用戶創(chuàng)建的相冊
PHFetchResult *topLevelUserCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
// 獲取所有資源的集合,并按照資源的創(chuàng)建時間排序
PHFetchOptions *options = [[PHFetchOptions alloc] init];
options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
PHFetchResult *assetsFetchResults = [PHASSet fetchAssetsWithOptions:options];
如前面提到過的那樣,從PHAssetCollection 中獲取到的可以使相冊也可以是資源,但無論是哪種內(nèi)容,都統(tǒng)一使用PHFetchResult 對象封裝起來,因此雖然PHAssetCollection 獲取到的結(jié)果可能是多樣的,但通過PHFetchResult 就可以使用統(tǒng)一的方法去處理這些內(nèi)容(即遍歷 PHFetchResult)。例如擴展上面的例子:
// 列出所有相冊智能相冊
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
for (NSInteger i = 0; i < fetchResult.count; i++) {
PHCollection *collection = fetchResult[i];
if (collection isKindOfClass:[PHAssetCollection class]]) {
PHAssetCollection *assetCollection = (PHAssetCollection *)collection;
PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:assetCollection options:fetchOptions];
} else {
NSAssert(NO, @"Fetch collection not PHCollection:%@", collection);
}
}
// 獲取所有資源的集合,并按資源的創(chuàng)建時間排序
PHFetchOptions *options = [[PHFetchOptions alloc] init];
options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
PHFetchResult *assetsFetchResults = [PHAsset fetchAssetsWithOptions:options];
// 這時 assetsFetchResults 中包含的,應(yīng)該就是各個資源(PHAsset)
for (NSInteger i = 0; i < fetchResult.count; i++) {
// 獲取一個資源(PHAsset)
PHAsset *asset = fetchResult[i];
}
<big><h2>2.獲取圖像的方式與坑點</h2></big>
經(jīng)過了上面的步驟,已經(jīng)可以了解到如何在 PhotoKit 中獲取到代表資源的 PHAsset 了,但與 ALAssetLibrary 中從 ALAsset 中直接獲取圖像的方式不同,PhotoKit 無法直接從 PHAsset 的實例中獲取圖像,而是引入了一個管理器?PHImageManager 獲取圖像。PHImageManager 是通過請求的方式拉取圖像,并可以控制請求得到的圖像的尺寸、剪裁方式、質(zhì)量,緩存以及請求本身的管理(發(fā)出請求、取消請求)等。而請求圖像的方法是 ?PHImageManager 的一個實例方法:
- (PHImageRequestID)requestImageForAsset:(PHAsset *)asset targetSize(CGSize)targetSize contentMode(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options resultHandler:(void (^)(UIImage *__nullable result, NSDictionary *__nullable info))resultHandler;
這個方法中的參數(shù)坑點不少,下面逐個參數(shù)列舉一下其作用及坑點:
- asset, 圖像對應(yīng)的 PHAsset。
- targetSize,需要獲取的圖像的尺寸,如果輸入的尺寸大于資源原圖的尺寸,則只會返回原圖。需要注意在 PHImageManager 中,所有的尺寸都是用 Pixel 作為單位,因此這里想要獲得正確大小的圖像,需要把輸入的尺寸轉(zhuǎn)化為 Pixel。如果返回原圖尺寸,可以傳入 PhotoKit 中預(yù)先定義好的常量PHImageManagerMaximumSize,表示返回可選范圍內(nèi)的最大尺寸,即原圖尺寸。
- contentMode,圖像的剪裁方式,與?UIView 的 contentMode 參數(shù)相似,控制照片應(yīng)該以按比例縮放還是按比例填充的方式放到最終展示的容器內(nèi)。注意如果 targetSize 傳入 PHImageManagerMaximumSize,則 contentMode 無論傳入什么值都會被視為?PHImageContentModeDefault。
- options,一個?PHImageRequestOptions 的實例,可以控制的內(nèi)容相當豐富,包括圖像的質(zhì)量、版本,也會有參數(shù)控制圖像的剪裁,下面再展開說明。
- resultHandler,請求結(jié)束后被調(diào)用的 block,返回一個包含資源對于圖像的 UIImage 和包含圖像信息的一個 NSDictionary, 在整個請求的周期中,這個block 可能會多次調(diào)用,關(guān)于這點連同 options 參數(shù)在下面展開說明。