AssetsLibrary的詳細(xì)使用
AssetsLibrary的組成
AssetsLibrary的組成和iPhone中相冊(cè)的實(shí)際組成十分的類似齐饮,AssetsLibrary庫(kù)中的類結(jié)構(gòu)對(duì)應(yīng)相冊(cè)中的相冊(cè)應(yīng)用指厌、相冊(cè)废累、相片或視頻财边,具體的類組成如下:
1.AssetsLibrary:代表iPhone中的資源庫(kù)(包含所有的photo围苫、video)俄精,可以這么認(rèn)為刁笙,AssetsLibrary就帶包iPhone中的相冊(cè)應(yīng)用改橘∽涛荆可以通過(guò)AssetsLibrary獲取所有的AssetsGroup。同時(shí)可以向資源庫(kù)中添加相冊(cè)飞主;
2.AssetsGroup:映射照片庫(kù)(AssetsLibrary)中的一個(gè)相冊(cè)狮惜,同過(guò)AssetsGroup可以獲取相冊(cè)相應(yīng)的信息,同時(shí)獲取可以通過(guò)相冊(cè)(AssetsGroup)獲取相冊(cè)下的資源碌识,同時(shí)也在當(dāng)前相冊(cè)下保存資源碾篡;
3.ALAsset:對(duì)應(yīng)相冊(cè)中的一張照片或者視頻,ALAsset包含了照片或視頻的詳細(xì)信息筏餐,可以通過(guò)ALAsset獲取縮略圖开泽。另一方面可以使用ALAsset的實(shí)例方法保存照片或視頻;
4.ALAssetRepresentation:ALAssetRepresentation 可以理解成是對(duì)ALAsset的封裝(但不是其子類)魁瞪,可以更方便地獲取 ALAsset 中的資源信息眼姐。通過(guò)ALAssetRepresentation可以獲取原圖诅迷、全屏圖。每個(gè) ALAsset 都有至少有一個(gè) ALAssetRepresentation 對(duì)象众旗,可以通過(guò) defaultRepresentation 獲取罢杉。而例如使用系統(tǒng)相機(jī)應(yīng)用拍攝的 RAW + JPEG 照片,則會(huì)有兩個(gè) ALAssetRepresentation贡歧,一個(gè)封裝了照片的 RAW 信息滩租,另一個(gè)則封裝了照片的 JPEG 信息。
AssetsLibrary一般用于定制一個(gè)圖片選擇器利朵,圖片選擇器相應(yīng)的可以實(shí)現(xiàn)多選律想、自定義界面。相應(yīng)的思路應(yīng)該是:
1.實(shí)例化照片庫(kù),列出所有相冊(cè)
2.展示相冊(cè)中的所有圖片
3.對(duì)選圖片或則點(diǎn)擊圖片預(yù)覽大圖绍弟。
因此AssetsLibrary的講解大體通過(guò)上面的過(guò)程來(lái)詳細(xì)的講解技即。
1. 實(shí)例化AssetsLibrary && AssetsLibrary類的詳解
1>實(shí)例化AssetsLibrary
實(shí)例化很簡(jiǎn)單,就普通的alloc init方法樟遣,如果你還想精簡(jiǎn)那就用new吧
ALAssetsLibrary * library = [[ALAssetsLibrary alloc] init];
2>遍歷照片庫(kù)(ALAssetsLibrary)中的所有相冊(cè)(AssetsGroup)
self.groups = [NSMutableArray array];
// 遍歷相冊(cè)
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if (group) { // 遍歷相冊(cè)還未結(jié)束
// 設(shè)置過(guò)濾器
[group setAssetsFilter:[ALAssetsFilter allPhotos]];
if (group.numberOfAssets) {
[self.groups addObject:group];
}
} else { // 遍歷結(jié)束(當(dāng)group為空的時(shí)候就意味著結(jié)束)
if (self.groups.count) {
// 如果相冊(cè)個(gè)數(shù)不為零而叼,則可以在此處開(kāi)始遍歷相冊(cè)了
//[self enumerateAssets];
} else {
NSLog(@"沒(méi)有相冊(cè)列表");
}
}
} failureBlock:^(NSError *error) {
NSLog(@"遍歷失敗");
}];
上面的代碼遍歷出了所有的相冊(cè),并把相冊(cè)中資源數(shù)量不為空的相冊(cè)對(duì)象(AssetsGroup)的應(yīng)用存儲(chǔ)到了一個(gè)數(shù)組中豹悬。
需要注意的是:
1.ALAssetsLibrary需要相冊(cè)為空葵陵,即相冊(cè)中沒(méi)有任何資源。如果你不想把為空的相冊(cè)保存到數(shù)組中瞻佛,可以通過(guò)AssetsGroup的numberOfAssets屬性判斷相冊(cè)是否為空脱篙,為空則不保存。
2.ALAssetsGroup有一個(gè)過(guò)濾器的實(shí)例方法:setAssetsFilter伤柄,通過(guò)此方法傳入的枚舉值绊困,可以設(shè)置只獲取相冊(cè)中的photo或者video。同時(shí)設(shè)置后适刀,或更新AssetsGroup對(duì)應(yīng)的numberOfAssets考抄。
3.在AssetsLibrary框架之下,所有的遍歷操作都是異步(Asynchronous)執(zhí)行的蔗彤。因?yàn)橛脩舻馁Y源庫(kù)川梅、相冊(cè)可能很大,這種條件之下然遏,異步遍歷不至于堵塞主線程寸爆。另外年扩,當(dāng)遍歷對(duì)應(yīng)的block中的輸出結(jié)果參數(shù)為空(nil)萤悴,則意味遍歷結(jié)束璧疗。當(dāng)然,通過(guò)給定的stop參數(shù),你也可以在滿足某種條件下手動(dòng)的停止遍歷怨酝。
2. 遍歷相冊(cè)(AssetsGroup)中的所有相片或視頻(Asset)
AssetsGroup提供了三種遍歷方式:
1.- (void)enumerateAssetsUsingBlock:
2.- (void)enumerateAssetsWithOptions:usingBlock:
3.- (void)enumerateAssetsAtIndexes:options:usingBlock:
遍歷相冊(cè):
- (void)enumerateAssets {
NSMutableArray * assets = [NSMutableArray new];
for (ALAssetsGroup * group in self.groups) {
/*
// 遍歷所有的相片
[group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result) { // 遍歷未結(jié)束
[assets addObject:result];
} else { // result 為nil傀缩,遍歷結(jié)束
}
}];
*/
// 遍歷指定的相片
NSInteger fromIndex = 0; // 重指定的index開(kāi)始遍歷
NSInteger toIndex =5; // 指定最后一張遍歷的index
[group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:toIndex] options:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (index > toIndex) { // 已經(jīng)遍歷到指定的最后一張照片
*stop = YES; // 停止遍歷
} else {
if (result) {
// 存儲(chǔ)相片
[assets addObject:result];
} else { // 遍歷結(jié)束
// 展示圖片
//[self showPhotoWith:result];
}
}
}];
}
}
遍歷相冊(cè)(ALAssetsGroup)中的照片(ALAsset)和遍歷資源庫(kù)(ALAssetsLibrary)中的相冊(cè)過(guò)程十分的類似,不過(guò)遍歷相冊(cè)中的照片更加的靈活农猬,可以通過(guò)enumerateAssetsUsingBlock: 遍歷所有的照片赡艰,同時(shí)可以通過(guò)enumerateAssetsAtIndexes:options:usingBlock:方法遍歷指定index的照片。這正如上面代碼中段注釋類是遍歷所有的照片斤葱,段注釋下面遍歷指定index一樣慷垮。
ALAssetsGroup的詳解
ALAssetsGroup代表的是一個(gè)相冊(cè),這個(gè)概念在上面已經(jīng)說(shuō)得夠詳細(xì)了揍堕,就不介紹了料身。在這里主要說(shuō)說(shuō)ALAssetsGroup類中的方法與屬性的含義和用法。
- (void)showALAssetsGroupInfo:(ALAssetsGroup *)assetsGroup {
// 是否可編輯,即相冊(cè)是否可以通過(guò)代碼添加相片
BOOL editable = assetsGroup.editable;
// 添加一個(gè)ALAsset到當(dāng)前相冊(cè),前提editable = YES衩茸,
[assetsGroup addAsset:nil];
/**
+ (ALAssetsFilter *)allPhotos; // 獲取Photo
+ (ALAssetsFilter *)allVideos; // 獲取Video
+ (ALAssetsFilter *)allAssets; // 獲取Photo還有video
*/
// 設(shè)置過(guò)濾器
[assetsGroup setAssetsFilter:[ALAssetsFilter allPhotos]];
// 當(dāng)前過(guò)濾器下的ALAsset數(shù)量
NSInteger number = assetsGroup.numberOfAssets;
/**
NSString *const ALAssetsGroupPropertyName; // Group的名稱
NSString *const ALAssetsGroupPropertyType; // Group類型(ALAssetsGroupType)
NSString *const ALAssetsGroupPropertyPersistentID;
NSString *const ALAssetsGroupPropertyURL; // 唯一表示這個(gè)Group的URL芹血,可以通過(guò)URL在資源庫(kù)中獲取對(duì)應(yīng)的Group,用于唯一標(biāo)識(shí)這個(gè)group
*/
// 通過(guò)Property獲取ALAssetsGroup對(duì)應(yīng)的信息
NSLog(@"%@", [assetsGroup valueForProperty:ALAssetsGroupPropertyName]);
NSLog(@"%@", [assetsGroup valueForProperty:ALAssetsGroupPropertyType]);
NSLog(@"%@", [assetsGroup valueForProperty:ALAssetsGroupPropertyPersistentID]);
NSLog(@"%@", [assetsGroup valueForProperty:ALAssetsGroupPropertyURL]);
// 獲取相冊(cè)封面
[assetsGroup posterImage];
}
3 獲取相片(ALAsset)中的詳細(xì)內(nèi)容
在這里需要詳細(xì)的說(shuō)明一下楞慈,所有的ALAsset所對(duì)應(yīng)的照片信息存在與ALAsset中的ALAssetRepresentation對(duì)象中幔烛,通過(guò)ALAssetRepresentation可以獲取這個(gè)ALAsset對(duì)應(yīng)的原圖、修改過(guò)后的圖抖部。而通過(guò)ALAsset可以獲取ALAsset對(duì)應(yīng)的縮略圖。另外需要說(shuō)明的是议惰,一個(gè)ALAsset可能對(duì)應(yīng)多個(gè)ALAssetRepresentation慎颗,原因在與相冊(cè)取圖的時(shí)候可能抓取多種不同格式的圖片,例如:RAW和JPEG格式的圖片言询,此時(shí)ALAsset就存在兩個(gè)ALAssetRepresentation俯萎,此時(shí)就可以通過(guò)不同的ALAssetRepresentation獲取不同格式的原圖、修改后的全屏圖运杭。
獲取原圖夫啊、全屏圖:
- (void)showPhotoWith:(ALAsset *)asset {
// 獲取ALAsset對(duì)應(yīng)的ALAssetRepresentation
ALAssetRepresentation * representation = [asset defaultRepresentation];
NSLog(@"%@", representation.url); // 圖片URL
NSLog(@"%@", NSStringFromCGSize(representation.dimensions)); // 圖片尺寸
NSLog(@"%lld", representation.size); // 數(shù)據(jù)字節(jié)
NSLog(@"%@", representation.UTI); // Uniform Type Identifier : 統(tǒng)一類型標(biāo)識(shí)符(表示圖片或視頻的類型)
NSLog(@"%@", representation.filename); // 在相冊(cè)中的文件名
NSLog(@"%@", representation.metadata); // 元數(shù)據(jù)(一些設(shè)備相關(guān)的信息,比如使用的相機(jī))
NSLog(@"%lf", representation.scale); // 縮放比例
NSLog(@"%ld", representation.orientation); // 方向
/**
fullScreenImage : 返回當(dāng)前設(shè)備尺寸大小的圖片辆憔,編輯后的圖片
fullResolutionImage : 原圖撇眯,沒(méi)有編輯的圖片
*/
// 獲取原圖
UIImage * image = [UIImage imageWithCGImage:[representation fullScreenImage] scale:1.0 orientation:UIImageOrientationDownMirrored];
self.imageView.image = image;
}
fullResolutionImage 是圖片的原圖,通過(guò) fullResolutionImage 獲取的圖片沒(méi)有任何處理虱咧,包括通過(guò)系統(tǒng)相冊(cè)中“編輯”功能處理后的信息也沒(méi)有被包含其中熊榛,因此需要展示“編輯”功能處理后的信息,使用 fullResolutionImage 就比較不方便腕巡,另外 fullResolutionImage 的拉取也會(huì)比較慢玄坦,在多張 fullResolutionImage 中切換時(shí)能明顯感覺(jué)到圖片的加載過(guò)程。因此這里建議獲取圖片的 fullScreenImage,它是圖片的全屏圖版本煎楣,這個(gè)版本包含了通過(guò)系統(tǒng)相冊(cè)中“編輯”功能處理后的信息豺总,同時(shí)也是一張縮略圖,但圖片的失真很少择懂,缺點(diǎn)是圖片的尺寸是一個(gè)適應(yīng)屏幕大小的版本喻喳,因此展示圖片時(shí)需要作出額外處理,但考慮到加載速度非承菪罚快的原因(在多張圖片之間切換感受不到圖片加載耗時(shí))沸枯,仍建議使用 fullScreenImage。
ALAsset詳解:
- (void)showALAssetInfoWith:(ALAsset *)asset {
/**
NSString *const ALAssetPropertyType;
NSString *const ALAssetPropertyLocation;
NSString *const ALAssetPropertyDuration;
NSString *const ALAssetPropertyOrientation;
NSString *const ALAssetPropertyDate;
NSString *const ALAssetPropertyRepresentations;
NSString *const ALAssetPropertyURLs;
NSString *const ALAssetPropertyAssetURL;
*/
NSLog(@"%@", [asset valueForProperty:ALAssetPropertyType]); // 這個(gè)type表示這個(gè)是photo還是video
NSLog(@"%@", [asset valueForProperty:ALAssetPropertyLocation]); // 拍攝的地點(diǎn)
NSLog(@"%@", [asset valueForProperty:ALAssetPropertyDuration]); // 視頻的時(shí)長(zhǎng)
NSLog(@"%@", [asset valueForProperty:ALAssetPropertyOrientation]); // 照片的方向
NSLog(@"%@", [asset valueForProperty:ALAssetPropertyDate]); // 照片的拍攝時(shí)間
NSLog(@"%@", [asset valueForProperty:ALAssetPropertyRepresentations]);
NSLog(@"%@", [asset valueForProperty:ALAssetPropertyURLs]); //
NSLog(@"%@", [asset valueForProperty:ALAssetPropertyAssetURL]);
[asset thumbnail]; // 返回縮略圖
[asset aspectRatioThumbnail]; // 等比例縮略圖
[asset representationForUTI:@"public.jpeg"]; // 通過(guò)統(tǒng)一類型標(biāo)識(shí)獲取ALAssetRepresentation
// ALAsset 還具有更改ALAsset中的元數(shù)據(jù)能力
// ALAsset 的實(shí)例方法能保存Photo赂弓、video到相冊(cè)
}
4. AssetsLibrary 的坑點(diǎn)
- AssetsLibrary 實(shí)例需要強(qiáng)引用
實(shí)例一個(gè) AssetsLibrary 后绑榴,如上面所示,我們可以通過(guò)一系列枚舉方法獲取到需要的相冊(cè)和資源盈魁,并把其儲(chǔ)存到數(shù)組中翔怎,方便用于展示。但是杨耙,當(dāng)我們把這些獲取到的相冊(cè)和資源儲(chǔ)存到數(shù)組時(shí)赤套,實(shí)際上只是在數(shù)組中儲(chǔ)存了這些相冊(cè)和資源在 AssetsLibrary 中的引用(指針),因而無(wú)論把相冊(cè)和資源儲(chǔ)存數(shù)組后如何利用這些數(shù)據(jù)珊膜,都首先需要確保 AssetsLibrary 沒(méi)有被 ARC 釋放容握,否則把數(shù)據(jù)從數(shù)組中取出來(lái)時(shí),會(huì)發(fā)現(xiàn)對(duì)應(yīng)的引用數(shù)據(jù)已經(jīng)丟失(參見(jiàn)下圖)车柠。這一點(diǎn)較為容易被忽略剔氏,因此建議在使用 AssetsLibrary 的 viewController 中,把 AssetsLibrary 作為一個(gè)強(qiáng)持有的 property 或私有變量竹祷,避免在枚舉出 AssetsLibrary 中所需要的數(shù)據(jù)后谈跛,AssetsLibrary 就被 ARC 釋放了。 - AssetsLibrary 遵循寫(xiě)入優(yōu)先原則
寫(xiě)入優(yōu)先也就是說(shuō)塑陵,在利用 AssetsLibrary 讀取資源的過(guò)程中感憾,有任何其它的進(jìn)程(不一定是同一個(gè) App)在保存資源時(shí),就會(huì)收到 ALAssetsLibraryChangedNotification令花,讓用戶自行中斷讀取操作阻桅。最常見(jiàn)的就是讀取 fullResolutionImage 時(shí),用進(jìn)程在寫(xiě)入兼都,由于讀取 fullResolutionImage 耗時(shí)較長(zhǎng)鳍刷,很容易就會(huì) exception。 - 開(kāi)啟 Photo Stream 容易導(dǎo)致 exception
本質(zhì)上俯抖,這跟上面的 AssetsLibrary 遵循寫(xiě)入優(yōu)先原則是同一個(gè)問(wèn)題输瓜。如果用戶開(kāi)啟了共享照片流(Photo Stream),共享照片流會(huì)以 mstreamd 的方式“偷偷”執(zhí)行,當(dāng)有人把相片寫(xiě)入 Camera Roll 時(shí)尤揣,它就會(huì)自動(dòng)保存到 Photo Stream Album 中搔啊,如果用戶剛好在讀取,那就跟上面說(shuō)的一樣產(chǎn)生 exception 了北戏。由于共享照片流是用戶決定是否要開(kāi)啟的负芋,所以開(kāi)發(fā)者無(wú)法改變,但是可以通過(guò)下面的接口在需要保護(hù)的時(shí)刻關(guān)閉監(jiān)聽(tīng)共享照片流產(chǎn)生的頻繁通知信息嗜愈。
[ALAssetsLibrary disableSharedPhotoStreamsSupport];