iOS開發之獲取照片&&TZImagePickerController的使用

由于前段時間,需要完成一個跟相冊的需求,所以閱讀了一些與圖片有關的文章,和使用了一些相關的第三方庫。

在 iOS 設備中,照片和視頻是相當重要的一部分。在 iOS 8 出現之前,開發者只能使用 AssetsLibrary 框架來訪問設備的照片庫,這是一個有點跟不上 iOS 應用發展步伐以及代碼設計原則但確實強大的框架,考慮到 iOS7 仍占有不少的滲透率,因此 AssetsLibrary 也是本文重點介紹的部分。隨著 iOS 8 的到來,蘋果給我們提供了一個現代化的框架 —— PhotoKit,它比 AssetsLibrary 表現更好,并且擁有讓應用和設備照片庫無縫工作的特性。

另外值得強調的是,在 iOS 中,照片庫并不只是照片的集合,同時也包含了視頻。在 AssetsLibrary 中兩者都有相同類型的對象去描述,只是類型不同而已。文中為了方便,大部分時候會使用「資源」代表 iOS 中的「照片和視頻」。

PhotoKit 對象模型

PhotoKit 定義了與系統的 Photos 應用內展現給用戶的模型對象相一致的實體圖表。這些照片實體都是輕量級的不可變對象。所有的 PhotoKit 對象都是繼承自 PHObject 抽象基類,其公共接口只提供了一個 localIdentifier 屬性。

PHObject.png

PHAsset

表示用戶照片庫中一個單獨的資源,用以提供資源的元數據。

成組的資源叫做資源集合,用 PHAssetCollection 類表示。一個單獨的資源集合可以是照片庫中的一個相冊或者一個時刻,或者是一個特殊的“智能相冊”。這種智能相冊包括所有的視頻集合,最近添加的項目,用戶收藏,所有連拍照片等等。PHAssetCollectionPHCollection 的子類。

PHCollectionList 表示一組的 PHCollections。因為它本身就是 PHCollection,所以集合列表可以包含其他集合列表,它們允許復雜的集合繼承。實際上,我們可以在照片應用的時刻欄目中看到它:照片 --- 時刻 --- 精選 --- 年度,就是一個例子。

PHAsset.png

獲取 (Fetch) 照片實體

獲取 vs. 枚舉
那些熟悉 AssetsLibrary 框架的開發者可能會記得 AssetsLibrary 可以用一些特定屬性來找到需要的資源,其中一個必須枚舉用戶資源庫來獲得匹配的資源。不得不承認,這個 API 雖然提供了一些縮小搜索域的方法,但還是十分低效。
而與之形成鮮明對比,PhotoKit 實體的實例是通過獲取得到的。那些熟悉 Core Data 的人,會覺得和 PhotoKit 在概念和描述都比較接近。
AssetsLibrary 的組成比較符合照片庫本身的組成,照片庫中的完整照片庫對象、相冊、相片都能在 AssetsLibrary 中找到一一對應的組成,這使到 AssetsLibrary 的使用變得直觀而方便。

AssetsLibrary: 代表整個設備中的資源庫(照片庫),通過 AssetsLibrary 可以獲取和包括設備中的照片和視頻

  • ALAssetsGroup: 映射照片庫中的一個相冊,通過 ALAssetsGroup 可以獲取某個相冊的信息,相冊下的資源,同時也可以對某個相冊添加資源。
  • ALAsset: 映射照片庫中的一個照片或視頻,通過 ALAsset 可以獲取某個照片或視頻的詳細信息,或者保存照片和視頻。
  • ALAssetRepresentation: ALAssetRepresentation 是對 ALAsset 的封裝(但不是其子類),可以更方便地獲取 ALAsset 中的資源信息,每個 ALAsset 都有至少有一個 ALAssetRepresentation 對象,可以通過 defaultRepresentation 獲取。而例如使用系統相機應用拍攝的 RAW + JPEG 照片,則會有兩個 ALAssetRepresentation,一個封裝了照片的 RAW 信息,另一個則封裝了照片的 JPEG 信息。

獲取請求
獲取操作是由上面描述的實體的類方法實現的。要使用哪個類/方法,取決于問題所在范圍和你展示與遍歷照片庫的方式。所有獲取方法的命名都是相似的:class func fetchXXX(..., options: PHFetchOptions) -> PHFetchResult 。options 參數給了我們一個對結果進行過濾和排序的途徑,這和 NSFetchRequestpredicatesortDescriptors 參數類似。

獲取結果
你可能已經注意到了這些獲取操作不是異步的。它們返回了一個 PHFetchResult 對象,可以用類似 NSArray 的接口來訪問結果內的集合。它會按需動態加載內容并且緩存最近請求的內容。這個行為和設置了 batchSize 屬性的 NSFetchRequest 返回的結果數組相似。對于 PHFetchResult 來說,沒有辦法用參數來指定這個行為,但是官網文檔保證 “即使在處理大量的返回結果時,依然能夠有最好的表現”。

PHFetchResult.png

PHImageManager 照片加載

在處理用戶照片庫的過去幾年中,開發者創造了上百 (如果沒有上千) 的小技巧來提高照片加載和展示的效率。這些技巧處理請求的派發和取消,圖像大小的修改和裁剪,緩存等等。PhotoKit 提供了一個可以用更加便捷和現代的 API 做了所有這些操作的類:PHImageManager
- (PHImageRequestID)requestImageForAsset:(PHAsset *)asset targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options resultHandler:(void (^)(UIImage *__nullable result, NSDictionary *__nullable info))resultHandler;
- (PHImageRequestID)requestImageDataForAsset:(PHAsset *)asset options:(nullable PHImageRequestOptions *)options resultHandler:(void(^)(NSData *__nullable imageData, NSString *__nullable dataUTI, UIImageOrientation orientation, NSDictionary *__nullable info))resultHandler;

PHImageRequestOptions 控制加載圖片時的參數

提供了一些方式來確定圖像管理器該以怎樣的方式來重新設置圖像大小。
resizeMode 屬性可以設置為 .Exact (返回圖像必須和目標大小相匹配),.Fast (比 .Exact 效率更高,但返回圖像可能和目標大小不一樣) 或者 .None
還有個值得一提的是,normalizedCroppingMode 屬性讓我們確定圖像管理器應該如何裁剪圖像。注意:如果設置了 normalizedcroppingMode 的值,那么 resizeMode 需要設置為 .Exact

結果回調 (result handler)

結果回調是一個包含了一個 UIImage 變量和一個 info 字典作為參數的 block。根據參數和請求的選項,在請求的整個生命周期,它可以被圖像管理器多次調用。

info 字典提供了關于當前請求狀態的信息,比如:

圖像是否必須從 iCloud 請求 (如果你初始化時將 networkAccessAllowed 設置成 false,那么就必須重新請求圖像) —— PHImageResultIsInCloudKey
當前遞送的 UIImage 是否是最終結果的低質量格式。當高質量圖像正在下載時,這個可以讓你給用戶先展示一個預覽圖像 —— PHImageResultIsDegradedKey
請求 ID (可以便捷的取消請求),以及請求是否已經被取消 —— PHImageResultRequestIDKeyPHImageCancelledKey
如果沒有圖像提供給 result handler,字典內還會有一個錯誤信息 —— PHImageErrorKey

TZImagePickerController(1.5.0)使用方法

方法一:

TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithSelectedAssets:_selectedAssets selectedPhotos:_selectedPhotos index:indexPath.row];
imagePickerVc.allowPickingOriginalPhoto = self.allowPickingOriginalPhotoSwitch.isOn;
imagePickerVc.isSelectOriginalPhoto = _isSelectOriginalPhoto;
[imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) {
    _selectedPhotos = [NSMutableArray arrayWithArray:photos];
    _selectedAssets = [NSMutableArray arrayWithArray:assets];
    _isSelectOriginalPhoto = isSelectOriginalPhoto;
    _layout.itemCount = _selectedPhotos.count;
    [_collectionView reloadData];
    _collectionView.contentSize = CGSizeMake(0, ((_selectedPhotos.count + 2) / 3 ) * (_margin + _itemWH));
}];

方法二:
首先遵守<TZImagePickerControllerDelegate>

TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:maxSelectCount delegate:self];
imagePickerVc.allowPickingOriginalPhoto = self.allowPickingOriginalPhotoSwitch.isOn;
imagePickerVc.isSelectOriginalPhoto = _isSelectOriginalPhoto;
imagePickerVc.sortAscendingByModificationDate = NO;
[self.navigationController presentViewController:imagePickerVc animated:YES completion:nil];

- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray<UIImage *> *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto {
    imagePickerVc.sortAscendingByModificationDate = NO;
    imagePickerVc.photoWidth = 1024.0;
    imagePickerVc.photoPreviewMaxWidth = 3072.0;
    [self.navigationController presentViewController:imagePickerVc animated:YES completion:nil];
}

注意:

1.在使用時,如果你不獲取原圖的話,TZImagePickerController的代理方法或block回調里返回的圖片是質量非常差的圖片,壓縮程度非常高。因為它是直接把PHImageResultIsDegradedKey里的圖片返回,從字面上我們就可以看出,這是蘋果返回的一個退化的圖片,我在前面也說了,這只是返回的一個預覽圖像,并且TZImagePickerController在創建PHImageRequestOptions的時候,resizeMode使用的是PHImageRequestOptionsResizeModeFast;如果把resizeMode修改成PHImageRequestOptionsResizeModeNone,可以適當的提高。
2.在外部設置photoPreviewMaxWidth超出500~800無效,因為TZImagePickerController在內部設置了范圍。
- (void)setPhotoPreviewMaxWidth:(CGFloat)photoPreviewMaxWidth {
_photoPreviewMaxWidth = photoPreviewMaxWidth;
if (photoPreviewMaxWidth > 800) {
_photoPreviewMaxWidth = 800;
} else if (photoPreviewMaxWidth < 500) {
_photoPreviewMaxWidth = 500;
}
[TZImageManager manager].photoPreviewMaxWidth = _photoPreviewMaxWidth;
}
所以,如果需要設置的話注意一下。

參考:
iOS 開發之照片框架詳解
objc中國-照片框架

由于長時間沒有去跟進 好多小伙伴的問題不能解決,萬分抱歉,大家有問題 可以提問,可能正好碰到有解決的 幫忙解答了,/::D/::D

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380