一. 最簡單的保存函數(shù)
- UIImage的函數(shù)來保存圖片
較為簡單, 只需要一個(gè)函數(shù)一個(gè)方法就可以保存
-
但是不能創(chuàng)建相冊, 保存的圖片會直接保存到默認(rèn)的系統(tǒng)相冊中
/** 該函數(shù)用于將圖片保存到系統(tǒng)相冊中 UIImage * _Nonnull image : 要保存的圖片 id _Nullable completionTarget : 調(diào)用completionSelector方法的對象, 一般為self SEL _Nullable completionSelector : 當(dāng)保存完成調(diào)用的方法, 是一個(gè)系統(tǒng)指定的方法 void * _Nullable contextInfo : 上下文信息, 用于傳給完成后的回調(diào)方法, 一般為nil */ UIImageWriteToSavedPhotosAlbum(_image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil); - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { if (error) { NSLog(@"保存失敗"); } else { NSLog(@"保存成功"); } }
-
注意點(diǎn)
- 第三個(gè)參數(shù)一定要使用系統(tǒng)的回調(diào)方法, 否則這個(gè)方法會報(bào)錯(cuò)
- 系統(tǒng)指定的
image: didFinishSavingWithError: contextInfo:
方法一定要實(shí)現(xiàn), 否則也會出現(xiàn)問題
二. 使用PHPhotoLibrary來保存圖片
-
框架的簡單介紹:
- PHPhotoLibrary類, 專門用于管理系統(tǒng)的相片, 相簿等功能, 他可以獲取系統(tǒng)相冊中的相片信息, 也可以將App中獲取的圖片/相片存到手機(jī)相冊中, 以及iCloud Photos中.
- 對于手機(jī)相冊的各種操作, 幾乎都是通過PHPhotoLibrary的單例對象, 在ChangeBlock中, 以
ChangeRequest
來執(zhí)行的- 相片請求操作: PHAssetChangeRequest
- 相冊請求操作: PHAssetCollectionChangeRequest
- 相冊列表請求操作: PHCollectionListChangeRequest(小的暫時(shí)沒試過)
- PHObjectPlaceholder對象
- 這個(gè)對象是用于存儲圖片時(shí)的占位對象
- 如果你想保存一個(gè)圖片到一個(gè)相冊中, 需要先將這個(gè)占位對象添加到相冊中, 當(dāng)ChangeBlock調(diào)用結(jié)束之后, 會根據(jù)占位對象的標(biāo)識符搜索到占位對象的所在位置, 然后在保存圖片
- PHAuthorization: 用于查看當(dāng)前App的相冊授權(quán)狀態(tài)
- 這個(gè)類用于獲取當(dāng)前你的App, 系統(tǒng)對其相冊訪問權(quán)限的授權(quán)狀態(tài)
- 通過對四種不同的授權(quán)狀態(tài)的判斷, 我們可以做出對應(yīng)的操作
- PHAuthorizationStatusNotDetermined : 用戶還沒有決定是否授權(quán)
- PHAuthorizationStatusRestricted : 訪問權(quán)限受限制, 這個(gè)很少見, 如家長模式的限制才會有
- PHAuthorizationStatusDenied : 用戶拒絕App訪問相冊
- PHAuthorizationStatusAuthorized : 用戶已經(jīng)授權(quán)了訪問
- PHFetchResult: 檢索相簿中的相冊/相片
- 這個(gè)類創(chuàng)建的對象, 是一個(gè)有序集合, 可以用于保存系統(tǒng)相簿中的相片/相冊的搜索結(jié)果列表
- 該對象的每個(gè)元素, 都有一個(gè)localizedTitle, 即搜索得到的相片/相冊的名稱, 可以通過這個(gè)屬性來獲得指定的相冊/相片
- 一般是通過遍歷的方式, 然后判斷l(xiāng)ocalizedTitle, 取得我們想要的相片/相冊
-
保存圖片的步驟
- 提供給外界調(diào)用的方法, 通過傳入要保存的圖片, 和指定的相冊名稱來保存一張圖片
在這個(gè)方法中, 要獲取當(dāng)前App的相冊授權(quán)狀態(tài)
如果用戶授權(quán)了, 就直接調(diào)用步驟2的方法, 保存圖片
如果用戶沒有確定是否授權(quán), 要創(chuàng)建授權(quán)申請, 讓用戶選擇
-
如果用戶已經(jīng)拒絕了授權(quán), 要顯示一個(gè)指示框, 讓用戶去打開授權(quán)
+ (void)saveImage:(UIImage *)image assetCollectionName:(NSString *)collectionName { // 1. 獲取當(dāng)前App的相冊授權(quán)狀態(tài) PHAuthorizationStatus authorizationStatus = [PHPhotoLibrary authorizationStatus]; // 2. 判斷授權(quán)狀態(tài) if (authorizationStatus == PHAuthorizationStatusAuthorized) { // 2.1 如果已經(jīng)授權(quán), 保存圖片(調(diào)用步驟2的方法) [self saveImage:image toCollectionWithName:collectionName]; } else if (authorizationStatus == PHAuthorizationStatusNotDetermined) { // 如果沒決定, 彈出指示框, 讓用戶選擇 [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { // 如果用戶選擇授權(quán), 則保存圖片 if (status == PHAuthorizationStatusAuthorized) { [self saveImage:image toCollectionWithName:collectionName]; } }]; } else { [SVProgressHUD showWithStatus:@"請?jiān)谠O(shè)置界面, 授權(quán)訪問相冊"]; } }
- 用于保存圖片的方法, 通過外接接口獲取到的圖片, 相冊名稱來進(jìn)行保存
將一個(gè)相片保存到一個(gè)自定義的相冊, 需要同時(shí)創(chuàng)建相片變動請求和相冊變動請求
根據(jù)傳入的相冊名, 要判斷一下當(dāng)前系統(tǒng)是否有這個(gè)相冊(這里需要步驟3的方法, 傳入相冊名稱, 來獲取相冊)
-
在這個(gè)步驟, 需要用到的四個(gè)核心對象為PHPhotoLibrary, PHAssetCollectionChangeRequest, PHAssetChangeRequest, 以及PHObjectPlaceholder
// 保存圖片 + (void)saveImage:(UIImage *)image toCollectionWithName:(NSString *)collectionName { // 1. 獲取相片庫對象 PHPhotoLibrary *library = [PHPhotoLibrary sharedPhotoLibrary]; // 2. 調(diào)用changeBlock [library performChanges:^{ // 2.1 創(chuàng)建一個(gè)相冊變動請求 PHAssetCollectionChangeRequest *collectionRequest; // 2.2 取出指定名稱的相冊 PHAssetCollection *assetCollection = [self getCurrentPhotoCollectionWithTitle:collectionName]; // 2.3 判斷相冊是否存在 if (assetCollection) { // 如果存在就使用當(dāng)前的相冊創(chuàng)建相冊請求 collectionRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection]; } else { // 如果不存在, 就創(chuàng)建一個(gè)新的相冊請求 collectionRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:collectionName]; } // 2.4 根據(jù)傳入的相片, 創(chuàng)建相片變動請求 PHAssetChangeRequest *assetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image]; // 2.4 創(chuàng)建一個(gè)占位對象 PHObjectPlaceholder *placeholder = [assetRequest placeholderForCreatedAsset]; // 2.5 將占位對象添加到相冊請求中 [collectionRequest addAssets:@[placeholder]]; } completionHandler:^(BOOL success, NSError * _Nullable error) { // 3. 判斷是否出錯(cuò), 如果報(bào)錯(cuò), 聲明保存不成功 if (error) { [SVProgressHUD showErrorWithStatus:@"保存失敗"]; } else { [SVProgressHUD showSuccessWithStatus:@"保存成功"]; } }]; }
- 步驟三用于獲取當(dāng)前系統(tǒng)中是否有指定的相冊
如果有的話, 就返回已有相冊
如果沒有的話, 就返回nil, 讓步驟二去創(chuàng)建一個(gè)新的系統(tǒng)相冊
此處需要用到的關(guān)鍵類為: FHFetchResult, 用于搜索相冊/相片名稱的集合對象
-
通過搜索結(jié)果的localizedTitle來找到對應(yīng)的相冊
+ (PHAssetCollection *)getCurrentPhotoCollectionWithTitle:(NSString *)collectionName { // 1. 創(chuàng)建搜索集合 PHFetchResult *result = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; // 2. 遍歷搜索集合并取出對應(yīng)的相冊 for (PHAssetCollection *assetCollection in result) { if ([assetCollection.localizedTitle containsString:collectionName]) { return assetCollection; } } return nil; }
- 提供給外界調(diào)用的方法, 通過傳入要保存的圖片, 和指定的相冊名稱來保存一張圖片