相冊管理

圖片視頻管理 AssetsLibrary

在ios8之前 ,只能使用AssetsLibrary 來訪問設(shè)備的照片庫 跃洛。
ios8之后际看,蘋果提供了PhotoKit 框架 。

需要注意,在ios中 厂抖,照片庫中既包含 圖片 ,也包含 視頻 。

--

AssetsLibrary 組成介紹

  • AssetsLibrary: 代表整個設(shè)備中的資源庫(照片庫)杈女,通過
  • AssetsLibrary 可以獲取和包括設(shè)備中的照片和視頻
  • ALAssetsGroup: 映射照片庫中的一個相冊,通過
  • ALAssetsGroup 可以獲取某個相冊的信息吊圾,相冊下的資源碧信,同時也可以對某個相冊添加資源。
  • ALAsset: 映射照片庫中的一個照片或視頻街夭,通過 ALAsset 可以獲取某個照片或視頻的詳細信息砰碴,或者保存照片和視頻。
  • ALAssetRepresentation: ALAssetRepresentation 是對 ALAsset 的封裝(但不是其子類)板丽,可以更方便地獲取 ALAsset 中的資源信息呈枉,每個 ALAsset 都有至少有一個 ALAssetRepresentation 對象,可以通過 defaultRepresentation 獲取埃碱。而例如使用系統(tǒng)相機應(yīng)用拍攝的 RAW + JPEG 照片猖辫,則會有兩個 ALAssetRepresentation,一個封裝了照片的 RAW 信息砚殿,另一個則封裝了照片的 JPEG 信息啃憎。

主要需要掌握的方法就是從相冊加載圖片

  • 首先是要檢查 App 是否有照片操作授權(quán):
NSString *tipTextWhenNoPhotosAuthorization; // 提示語
// 獲取當(dāng)前應(yīng)用對照片的訪問授權(quán)狀態(tài)
ALAuthorizationStatus authorizationStatus = [ALAssetsLibrary authorizationStatus];
// 如果沒有獲取訪問授權(quán),或者訪問授權(quán)狀態(tài)已經(jīng)被明確禁止似炎,則顯示提示語辛萍,引導(dǎo)用戶開啟授權(quán)
if (authorizationStatus == ALAuthorizationStatusRestricted || authorizationStatus == ALAuthorizationStatusDenied) {
    NSDictionary *mainInfoDictionary = [[NSBundle mainBundle] infoDictionary];
    NSString *appName = [mainInfoDictionary objectForKey:@"CFBundleDisplayName"];
    tipTextWhenNoPhotosAuthorization = [NSString stringWithFormat:@"請在設(shè)備的\"設(shè)置-隱私-照片\"選項中,允許%@訪問你的手機相冊", appName];
    // 展示提示語
}
  • 獲取相冊列表
_assetsLibrary = [[ALAssetsLibrary alloc] init];
_albumsArray = [[NSMutableArray alloc] init];
[_assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
    if (group) {
        [group setAssetsFilter:[ALAssetsFilter allPhotos]];
        if (group.numberOfAssets > 0) {
            // 把相冊儲存到數(shù)組中羡藐,方便后面展示相冊時使用
            [_albumsArray addObject:group];
        }
    } else {
        if ([_albumsArray count] > 0) {
            // 把所有的相冊儲存完畢贩毕,可以展示相冊列表
        } else {
            // 沒有任何有資源的相冊,輸出提示
        }
    }
} failureBlock:^(NSError *error) {
    NSLog(@"Asset group not found!\n");
}];

這里需要的主意

1 iOS 中允許相冊為空仆嗦,即相冊中沒有任何資源辉阶,如果不希望獲取空相冊,則需要像上面的代碼中那樣手動過濾
2 ALAssetsGroup 有一個 setAssetsFilter 的方法,可以傳入一個過濾器谆甜,控制只獲取相冊中的照片或只獲取視頻垃僚。一旦設(shè)置過濾,ALAssetsGroup 中資源列表和資源數(shù)量的獲取也會被自動更新规辱。
3 整個 AssetsLibrary 中對相冊冈在、資源的獲取和保存都是使用異步處理(Asynchronous),這是考慮到資源文件體積相當(dāng)比較大(還可能很大)按摘。例如上面的遍歷相冊操作包券,相冊的結(jié)果使用 block 輸出,如果相冊遍歷完畢炫贤,則最后一次輸出的 block 中的 group 參數(shù)值為 nil溅固。而 stop 參數(shù)則是用于手工停止遍歷,只要把 *stop 置 YES兰珍,則會停止下一次的遍歷侍郭。關(guān)于這一點常常會引起誤會,所以需要注意掠河。

  • 接下來是獲取相冊中的資源:
_imagesAssetArray = [[NSMutableArray alloc] init];
[assetsGroup enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
    if (result) {
        [_imagesAssetArray addObject:result];
    } else {
        // result 為 nil亮元,即遍歷相片或視頻完畢,可以展示資源列表
    }
}];

跟遍歷相冊的過程類似唠摹,遍歷相片也是使用一系列的異步方法爆捞,其中上面的方法所輸出的 block 中,除了 result 參數(shù)表示資源信息勾拉,stop 用于手工停止遍歷外煮甥,還提供了一個 index 參數(shù),這個參數(shù)表示資源的索引藕赞。一般來說成肘,展示資源列表都會使用縮略圖(result.thumbnail),因此即使資源很多斧蜕,遍歷資源的速度也會相當(dāng)快双霍。但如果確實需要加載資源的高清圖或者其他耗時的處理,則可以利用上面的 index 參數(shù)和 stop 參數(shù)做一個分段拉取資源批销。例如:

NSUInteger _targetIndex; // index 目標(biāo)值洒闸,拉取資源直到這個值就手工停止拉取
NSUInteger _currentIndex; // 當(dāng)前 index,每次拉取資源時從這個值開始
 
_targetIndex = 50;
_currentIndex = 0;
 
- (void)loadAssetWithAssetsGroup:(assetsGroup *)assetsGroup {
    [assetsGroup enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:_currentIndex] options:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
        _currentIndex = index;
        if (index > _targetIndex) {
            // 拉取資源的索引如果比目標(biāo)值大风钻,則停止拉取
            *stop = YES;
        } else {
            if (result) {
                [_imagesAssetArray addObject:result];
            } else {
                // result 為 nil顷蟀,即遍歷相片或視頻完畢
            }
        }
    }];
}
 
// 之前拉取的數(shù)據(jù)已經(jīng)顯示完畢,需要展示新數(shù)據(jù)骡技,重新調(diào)用 loadAssetWithAssetsGroup
  • 最后是獲取圖片的詳情
// 獲取資源圖片的詳細資源信息,其中 imageAsset 是某個資源的 ALAsset 對象
ALAssetRepresentation *representation = [imageAsset defaultRepresentation];
// 獲取資源圖片的 fullScreenImage
UIImage *contentImage = [UIImage imageWithCGImage:[representation fullScreenImage]];

對于一個 ALAssetRepresentation,里面包含了圖片的多個版本布朦。最常用的是 fullResolutionImage 和 fullScreenImage囤萤。fullResolutionImage 是圖片的原圖,通過 fullResolutionImage 獲取的圖片沒有任何處理是趴,包括通過系統(tǒng)相冊中“編輯”功能處理后的信息也沒有被包含其中涛舍,因此需要展示“編輯”功能處理后的信息,使用 fullResolutionImage 就比較不方便唆途,另外 fullResolutionImage 的拉取也會比較慢富雅,在多張 fullResolutionImage 中切換時能明顯感覺到圖片的加載過程。因此這里建議獲取圖片的 fullScreenImage肛搬,它是圖片的全屏圖版本没佑,這個版本包含了通過系統(tǒng)相冊中“編輯”功能處理后的信息,同時也是一張縮略圖温赔,但圖片的失真很少蛤奢,缺點是圖片的尺寸是一個適應(yīng)屏幕大小的版本,因此展示圖片時需要作出額外處理陶贼,但考慮到加載速度非称》罚快的原因(在多張圖片之間切換感受不到圖片加載耗時),仍建議使用 fullScreenImage拜秧。

系統(tǒng)相冊的處理過程大概也是如上痹屹,可以看出,在整個過程中并沒有使用到圖片的 fullResolutionImage枉氮,從相冊列表展示到最終查看資源痢掠,都是使用縮略圖,這也是 iOS 相冊加載快的一個重要原因嘲恍。

--

補充

獲取原圖
CGImageRef fullResolutionImageRef = [[(ALAsset *)asset defaultRepresentation] fullResolutionImage];
//        // 通過 fullResolutionImage 獲取到的的高清圖實際上并不帶上在照片應(yīng)用中使用“編輯”處理的效果足画,需要額外在 AlAssetRepresentation 中獲取這些信息
        NSString *adjustment = [[[(ALAsset *)asset defaultRepresentation] metadata] objectForKey:@"AdjustmentXMP"];
        if (adjustment) {
            // 如果有在照片應(yīng)用中使用“編輯”效果,則需要獲取這些編輯后的濾鏡佃牛,手工疊加到原圖中
            NSData *xmpData = [adjustment dataUsingEncoding:NSUTF8StringEncoding];
            CIImage *tempImage = [CIImage imageWithCGImage:fullResolutionImageRef];
            
            NSError *error;
            NSArray *filterArray = [CIFilter filterArrayFromSerializedXMP:xmpData
                                                         inputImageExtent:tempImage.extent
                                                                    error:&error];
            CIContext *context = [CIContext contextWithOptions:nil];
            if (filterArray && !error) {
                for (CIFilter *filter in filterArray) {
                    [filter setValue:tempImage forKey:kCIInputImageKey];
                    tempImage = [filter outputImage];
                }
                fullResolutionImageRef = [context createCGImage:tempImage fromRect:[tempImage extent]];
            }
        }
        // 生成最終返回的 UIImage淹辞,同時把圖片的 orientation 也補充上去
        resultImage = [UIImage imageWithCGImage:fullResolutionImageRef
                                          scale:[[asset defaultRepresentation] scale]
                                    orientation:(UIImageOrientation)[[asset defaultRepresentation] orientation]];

帶一個block參數(shù) 作為輸入值 ,函數(shù)之行到block 俘侠。就會調(diào)用block 象缀。也就是回調(diào)block 。

    `[[XMNPhotoManager sharedManager] getOriginImageWithAsset:self.asset completionBlock:^(UIImage *image){
    resultImage = image;
}];

`

- (void)getOriginImageWithAsset:(id _Nonnull)asset completionBlock:(void(^_Nonnull)(UIImage * _Nullable image))completionBlock;
這段代碼就是manger 之行方法爷速,會調(diào)用block (這個block 需要一個image輸入值)央星。

manger 就是 用一個image 來調(diào)用block 。最后block 就回調(diào)他自己的代碼塊 { resultImage = image; }];
實現(xiàn)了image 從 manger 到其它類的 異步傳遞 惫东。

相冊管理 PhotoKit

  • PHAsset: 代表照片庫中的一個資源莉给,跟 ALAsset 類似毙石,通過 PHAsset 可以獲取和保存資源
  • PHFetchOptions: 獲取資源時的參數(shù),可以傳 nil颓遏,即使用系統(tǒng)默認值
  • PHFetchResult: 表示一系列的資源集合徐矩,也可以是相冊的集合
  • PHAssetCollection: 表示一個相冊或者一個時刻,或者是一個「智能相冊(系統(tǒng)提供的特定的一系列相冊叁幢,例如:最近刪除滤灯,視頻列表,收藏等等)
  • PHImageManager: 用于處理資源的加載曼玩,加載圖片的過程帶有緩存處理鳞骤,可以通過傳入一個 PHImageRequestOptions 控制資源的輸出尺寸等規(guī)格
  • PHImageRequestOptions: 如上面所說,控制加載圖片時的一系列參數(shù)
// 列出所有相冊智能相冊
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];
 
// 在資源的集合中獲取第一個集合豫尽,并獲取其中的圖片
PHCachingImageManager *imageManager = [[PHCachingImageManager alloc] init];
PHAsset *asset = assetsFetchResults[0];
[imageManager requestImageForAsset:asset
                         targetSize:SomeSize
                        contentMode:PHImageContentModeAspectFill
                            options:nil
                      resultHandler:^(UIImage *result, NSDictionary *info) {
                           
                          // 得到一張 UIImage,展示到界面上
                           
                      }];
  • 從 AssetsLibrary 中獲取數(shù)據(jù)样悟,無論是相冊拂募,還是資源,本質(zhì)上都是使用枚舉的方式窟她,遍歷照片庫取得相應(yīng)的數(shù)據(jù)陈症。而 PhotoKit 則是通過傳入?yún)?shù),直接獲取相應(yīng)的數(shù)據(jù)震糖,因而效率會提高不少录肯。
  • 在 AssetsLibrary 中,相冊和資源是對應(yīng)不同的對象(ALAssetGroup 和 ALAsset)吊说,因此獲取相冊和獲取資源是兩個完全沒有關(guān)聯(lián)的接口论咏。而 PhotoKit 中則有 PHFetchResult 這個可以統(tǒng)一儲存相冊或資源的對象,因此處理相冊和資源時也會比較方便颁井。
  • PhotoKit 返回資源結(jié)果時厅贪,同時返回了資源的元數(shù)據(jù),獲取元數(shù)據(jù)在 AssetsLibrary 中是很難辦到的一件事雅宾。同時通過 PHAsset养涮,開發(fā)者還能直接獲取資源是否被收藏(favorite)和隱藏(hidden),拍攝圖片時是否開啟了 HDR 或全景模式眉抬,甚至能通過一張連拍圖片獲取到連拍圖片中的其他圖片贯吓。這也是文章開頭說的,PhotoKit 能更好地與設(shè)備照片庫接入的一個重要因素蜀变。

一個很棒的圖片選擇器

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末悄谐,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子库北,更是在濱河造成了極大的恐慌爬舰,老刑警劉巖们陆,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異洼专,居然都是意外死亡棒掠,警方通過查閱死者的電腦和手機孵构,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門屁商,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人颈墅,你說我怎么就攤上這事蜡镶。” “怎么了恤筛?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵官还,是天一觀的道長。 經(jīng)常有香客問我毒坛,道長望伦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任煎殷,我火速辦了婚禮屯伞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘豪直。我一直安慰自己劣摇,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布弓乙。 她就那樣靜靜地躺著末融,像睡著了一般。 火紅的嫁衣襯著肌膚如雪暇韧。 梳的紋絲不亂的頭發(fā)上勾习,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音懈玻,去河邊找鬼巧婶。 笑死,一個胖子當(dāng)著我的面吹牛酪刀,可吹牛的內(nèi)容都是我干的粹舵。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼骂倘,長吁一口氣:“原來是場噩夢啊……” “哼眼滤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起历涝,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤诅需,失蹤者是張志新(化名)和其女友劉穎漾唉,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體堰塌,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡赵刑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了场刑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片般此。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖牵现,靈堂內(nèi)的尸體忽然破棺而出铐懊,到底是詐尸還是另有隱情,我是刑警寧澤瞎疼,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布科乎,位于F島的核電站,受9級特大地震影響贼急,放射性物質(zhì)發(fā)生泄漏茅茂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一太抓、第九天 我趴在偏房一處隱蔽的房頂上張望空闲。 院中可真熱鬧,春花似錦腻异、人聲如沸进副。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽影斑。三九已至,卻和暖如春机打,著一層夾襖步出監(jiān)牢的瞬間矫户,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工残邀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留皆辽,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓芥挣,卻偏偏與公主長得像驱闷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子空免,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容