一、保存圖片到自定義相冊(cè)的三個(gè)步驟
-
1.保存圖片到相冊(cè)【相機(jī)膠卷】
1>、C語(yǔ)言保存
2>、#import <AssetsLibrary/AssetsLibrary.h> 保存AssetsLibrary框架: iOS9 之后開(kāi)始被廢棄
3>、#import <Photos/Photos.h> 保存
Photos框架 iOS 8 開(kāi)始就可以用了
2.擁有一個(gè)自定義相冊(cè):使用
AssetsLibrary與Photos框架3.將剛才保存到【相機(jī)膠卷中的圖片】引用到【自定義的相冊(cè)】:使用
AssetsLibrary與Photos框架
二、單純的C語(yǔ)言保存圖片到相冊(cè)(不使用AssetsLibrary與Photos框架)
-
2.1、保存圖片到相冊(cè)
/** <#Description#> 第1個(gè)參數(shù):UIIMage 對(duì)象 第2個(gè)參數(shù):監(jiān)聽(tīng)對(duì)象 第3個(gè)參數(shù):保存后所走【監(jiān)聽(tīng)對(duì)象】的方法 第4個(gè)參數(shù):描述文字,一般為 niul */ UIImageWriteToSavedPhotosAlbum(self.photoimageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil); #pragma mark 保存成功后所走的方法 - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{ // 保存完畢 if (error) { NSLog(@"保存失敗"); }else{ NSLog(@"保存成功"); } }提示:上面第三個(gè)參數(shù)是要按照蘋(píng)果的格式來(lái)寫(xiě)方法名的,點(diǎn)擊方法進(jìn)去 我們可以到如下代碼:
// Adds a photo to the saved photos album. The optional completionSelector should have the form:
// - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;
蘋(píng)果讓我們按照他們的格式來(lái)寫(xiě)方法,我們可以把他們的方法名替換為任意的名字,如:- (void)a:(UIImage *)image b:(NSError *)error c:(void *)contextInfo;
三、Photos 框架
-
3.1、Photos 框架基本認(rèn)識(shí),我們可以在
Help->Developer Documentation-> 選擇OC或者Swift 搜索Photos
Photos 框架檢索
Photos 是用來(lái)處理 視頻 與 圖片 的,下面是其主要的類(lèi)-
<1>、
PHAsset:一個(gè) PHAsset 對(duì)象就代表相冊(cè)中的一張圖片或者一個(gè)視頻(1)、查:[PHAsset fetch.....]
(2)、增刪改:PHAssetChangeRequest,改變圖片 (包括 圖片/視頻 相關(guān)的所有改動(dòng)操作) <2>、:
PHAssetCollection: 一個(gè)PHAssetCollection就代表一個(gè)相冊(cè)
(1)、查:[PHAssetCollection fetch.....]
(2)、增刪改:PHAssetCollectionChangeRequest,改變相冊(cè) (包括 相冊(cè) 相關(guān)的所有改動(dòng)操作)
提示:所有的增刪改的操作都要放到:
-[PHPhotoLibrary performChanges:completionHandler:] or -[PHPhotoLibrary performChangesAndWait:error:]'方法里面 -
-
3.2、使用 Photos 框架保存圖片到【相機(jī)膠卷】
-
異步操作保存到相冊(cè)
[[PHPhotoLibrary sharedPhotoLibrary]performChanges:^{ [PHAssetChangeRequest creationRequestForAssetFromImage:self.photoimageView.image]; } completionHandler:^(BOOL success, NSError * _Nullable error) { if (error) { [SVProgressHUD showErrorWithStatus:@"保存失敗"]; }else{ [SVProgressHUD showErrorWithStatus:@"保存成功"]; } }]; -
同步操作保存到相冊(cè)
NSError *error = nil; [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ [PHAssetChangeRequest creationRequestForAssetFromImage:self.photoimageView.image]; } error:&error]; if (error) { [SVProgressHUD showErrorWithStatus:@"保存失敗"]; }else{ [SVProgressHUD showErrorWithStatus:@"保存成功"]; }
提示:使用 Photos 框架保存圖片到【相機(jī)膠卷】必須把代碼放到上面的兩個(gè)方法里面,否則會(huì)報(bào)下面的錯(cuò)
reason: 'This method can only be called from inside of -[PHPhotoLibrary performChanges:completionHandler:] or -[PHPhotoLibrary performChangesAndWait:error:]' -
-
3.3、創(chuàng)建新的相冊(cè)(自定義一個(gè)屬于自己app的相冊(cè)),提示:創(chuàng)建相冊(cè)之前要先判斷相冊(cè)是否存在,存在就不再創(chuàng)建
NSError *error = nil; [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ // 獲取app的名字 NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; // 創(chuàng)建一個(gè)自定義的相冊(cè) [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle: appName]; } error:&error]; if (error) { [SVProgressHUD showErrorWithStatus:@"創(chuàng)建相冊(cè)失敗"]; }else{ [SVProgressHUD showErrorWithStatus:@"創(chuàng)建相冊(cè)成功"]; }提示一:
kCFBundleNameKey = @"CFBundleName",下面的兩句是一個(gè)意思- NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
下面是:C 的strting轉(zhuǎn)為NSString - NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleNameKey];
提示二:Foundation 和 Core Foundation 的數(shù)據(jù)類(lèi)型可以相互轉(zhuǎn)換,比如:NSString * 和 CFStringRef,如下面的例子:
NSString *string = (NSString *)kCFBundleNameKey; CFStringRef string = (CFStringRef)@"name"; - NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
-
3.4、查詢(xún)相冊(cè) (自定義相冊(cè)或者系統(tǒng)相冊(cè))
/** PHAssetCollectionTypeAlbum = 1, 自定義相冊(cè)(普通的相冊(cè)) PHAssetCollectionTypeSmartAlbum = 2, 智能相冊(cè)(系統(tǒng)自帶的相冊(cè)),如:Camera Roll PHAssetCollectionTypeMoment = 3, 按照時(shí)刻分的相冊(cè) */ // 相機(jī)膠卷相冊(cè),打?。篊amera Roll // PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil]; // 自定義相冊(cè),打?。鹤远x相冊(cè)的名字 PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; for (PHAssetCollection *collection in collections) { NSLog(@"相冊(cè)的名字=%@",collection.localizedTitle); } -
3.5.創(chuàng)建相冊(cè)與查詢(xún)相冊(cè)合在一起,如下
// 獲取app的名字 NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; /** PHAssetCollectionTypeAlbum = 1, 自定義相冊(cè)(普通的相冊(cè)) PHAssetCollectionTypeSmartAlbum = 2, 智能相冊(cè)(系統(tǒng)自帶的相冊(cè)),如:Camera Roll PHAssetCollectionTypeMoment = 3, 按照時(shí)刻分的相冊(cè) */ // 相機(jī)膠卷相冊(cè),打印:Camera Roll // PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil]; // 自定義相冊(cè),打印:自定義相冊(cè)的名字 PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; // 自己的相冊(cè) PHAssetCollection *appCollection = nil; for (PHAssetCollection *collection in collections) { NSLog(@"相冊(cè)的名字=%@",collection.localizedTitle); if ([collection.localizedTitle isEqualToString:appName]) { appCollection = collection; break; } } if (appCollection == nil) { NSError *error = nil; __block NSString *createCollectionID = nil; [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ // 獲取app的名字 NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; // 獲取相冊(cè)的唯一標(biāo)識(shí)符 createCollectionID = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:appName].placeholderForCreatedAssetCollection.localIdentifier; } error:&error]; if (error) { [SVProgressHUD showErrorWithStatus:@"創(chuàng)建相冊(cè)失敗"]; }else{ appCollection = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[createCollectionID] options:nil].firstObject; [SVProgressHUD showErrorWithStatus:@"創(chuàng)建相冊(cè)成功"]; } } // 相冊(cè)一定存在 NSLog(@"相冊(cè)已經(jīng)存在");提示:這里有一個(gè)技術(shù)點(diǎn)就是:根據(jù)創(chuàng)建相冊(cè)返回的相冊(cè)唯一標(biāo)識(shí)符獲取相冊(cè)對(duì)象,如下代碼:
// 自己的相冊(cè) PHAssetCollection *appCollection = nil; if (appCollection == nil) { NSError *error = nil; __block NSString *createCollectionID = nil; [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ // 獲取app的名字 NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; // 獲取相冊(cè)的唯一標(biāo)識(shí)符 createCollectionID = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:appName].placeholderForCreatedAssetCollection.localIdentifier; } error:&error]; if (error) { [SVProgressHUD showErrorWithStatus:@"創(chuàng)建相冊(cè)失敗"]; }else{ appCollection = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[createCollectionID] options:nil].firstObject; [SVProgressHUD showErrorWithStatus:@"創(chuàng)建相冊(cè)成功"]; } }- 再次提示:只有上面的block代碼執(zhí)行完才代表相冊(cè)可能存在,所以,獲取PHAssetCollection放在了下面
-
3.6、保存圖片到自定義的相冊(cè)
-(void)savePhotosToAppPhotoCollection{ // 同步操作保存到【相機(jī)膠卷】 __block PHObjectPlaceholder *placeholderForCreatedAsset; NSError *error = nil; [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ placeholderForCreatedAsset = [PHAssetChangeRequest creationRequestForAssetFromImage:self.photoimageView.image].placeholderForCreatedAsset; } error:&error]; if (error) { [SVProgressHUD showErrorWithStatus:@"保存圖片失敗"]; return; } // 獲得自定義相冊(cè) PHAssetCollection *createCollection = [JKPhotosKit createPHAssetCollection]; if (createCollection == nil) { [SVProgressHUD showErrorWithStatus:@"創(chuàng)建相冊(cè)失敗"]; return; } // 添加剛才保存的圖片到 【自定義相冊(cè)】 [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ // 獲取自定義對(duì)象的操作對(duì)象 PHAssetCollectionChangeRequest *request = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:createCollection]; // 把圖片插入到自定義相冊(cè)的第一個(gè)位置 [request insertAssets:@[placeholderForCreatedAsset] atIndexes:[NSIndexSet indexSetWithIndex:0]]; } error:&error]; if (error) { [SVProgressHUD showErrorWithStatus:@"保存圖片失敗"]; }else{ [SVProgressHUD showSuccessWithStatus:@"保存圖片成功"]; } } -
3.7、用戶(hù)相冊(cè)權(quán)限的判斷
// 請(qǐng)求或者訪(fǎng)問(wèn)用戶(hù)訪(fǎng)問(wèn)權(quán)限: // 如果還沒(méi)有做出選擇,會(huì)自動(dòng)彈框,用戶(hù)對(duì)彈框做出選擇后才會(huì)調(diào)用block; // 如果用戶(hù)之前已經(jīng)做出過(guò)選擇,會(huì)自動(dòng)執(zhí)行block /** PHAuthorizationStatusNotDetermined = 0,還沒(méi)決定 PHAuthorizationStatusRestricted = 1,沒(méi)有授權(quán),不能訪(fǎng)問(wèn)用戶(hù)相冊(cè) PHAuthorizationStatusDenied = 2,用戶(hù)拒絕這個(gè)應(yīng)用 PHAuthorizationStatusAuthorized = 3 用戶(hù)授權(quán)這個(gè)app訪(fǎng)問(wèn)這個(gè)相冊(cè) */ // 獲取用戶(hù)之前的狀態(tài) PHAuthorizationStatus oldStatus = [PHPhotoLibrary authorizationStatus]; [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { // 用戶(hù)決絕當(dāng)前 App 訪(fǎng)問(wèn)相冊(cè) dispatch_async(dispatch_get_main_queue(), ^{ if (status == PHAuthorizationStatusDenied) { if (oldStatus != PHAuthorizationStatusDenied) { // 提醒用戶(hù)打開(kāi)開(kāi)關(guān) }else{ } }else if (status == PHAuthorizationStatusAuthorized){ // 用戶(hù)允許當(dāng)前 App 訪(fǎng)問(wèn)相冊(cè) [self trueSaveImageToAppPhotoCollection:saveImage]; }else if (status == PHAuthorizationStatusRestricted){ // 因系統(tǒng)原因無(wú)法訪(fǎng)問(wèn)相冊(cè) [SVProgressHUD showErrorWithStatus:@"因系統(tǒng)原因無(wú)法訪(fǎng)問(wèn)相冊(cè)"]; } }); }];提示:上面所有的完整代碼都在
JKPhotosKit類(lèi)里面,需要的請(qǐng)下載 demo- JKPhotosKit 類(lèi)的使用方法:保存圖片到自定的相冊(cè)
[JKPhotosKit savePhotosToAppPhotoCollection:UIImage對(duì)象];
效果圖
- JKPhotosKit 類(lèi)的使用方法:保存圖片到自定的相冊(cè)
完整代碼都在 JKPhotosKit類(lèi)里面,需要的請(qǐng)下載 demo

