我們在APP中點擊照片,都會顯示出大圖,然后在大圖的上面會有個保存照片的按鈕,照片直接保存到了系統的相冊中,但是因為公司產品的需要,讓你創建和APP同名的相冊保存在里面,那么就對了,可以看下具體的代碼和思路,然后把代碼直接拿過去就可以用了,對,沒錯,站在巨人的肩膀上編程
一共有兩種方法自定義相冊
第一種是iOS9之后過期的 <AssetsLibrary/AssetsLibrary.h>蘋果原生框架 第二種是iOS8推出的<Photos/Photos.h> 蘋果原生框架,功能更多,但是只支持iOS8之后的版本 一般推薦使用<Photos/Photos.h> ,因為現在版本快iOS10了,有些版本沒有升級的用戶已經可以拋棄了
1.添加圖片到【相機膠卷】 1> UIImageWriteToSavedPhotosAlbum函數 2> AssetsLibrary框架 3> Photos框架(推薦) 2.擁有一個【自定義相冊】 1> AssetsLibrary框架 2> Photos框架(推薦) 3.將剛才添加到【相機膠卷】的圖片,引用(添加)到【自定義相冊】 1> AssetsLibrary框架 2> Photos框架(推薦)
One:
如果只需要將要將圖片保存到系統的相冊中,只需要下面兩句代碼就搞定了
#文檔里已經說明這個方法是保存到用戶的相機膠卷里面的 Adds the specified image to the user’s Camera Roll album. - (void)saveBtns { // /** // * 保存到相冊的方法 // * @param image#> 需要保存的圖片 // * @param completionTarget#> 哪個控制器 description#> // * @param completionSelector#> 哪個方法 點擊方法文檔里面有提示 description#> // * @param contextInfo#> 參數,傳什么現實什么 description#> // * @return // */ UIImageWriteToSavedPhotosAlbum(self.imageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), @"傳什么下面就調用什么什么"); } // 需要實現下面的方法,或者傳入三個參數即可 - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { if (error) { [SVProgressHUD showErrorWithStatus:@"保存失敗"]; }else { [SVProgressHUD showSuccessWithStatus:@"保存成功"]; } } #注意: @selector() 方法一定要傳入三個參數,不然圖片雖然保存進去了,但是會崩了 因為參數越界 實參個數 > 形參個數, 就會出現參數越界 -[NSInvocation setArgument:atIndex:]: index (2) out of bounds [-1, 1] :
Two:
需要用到<AssetsLibrary/AssetsLibrary.h>這個庫

官方文檔給出的提示
//自定相冊的類 #import <AssetsLibrary/AssetsLibrary.h> static NSString *kGroupNameKey = @"nameKey"; static NSString *kDefaultGroupName = @"會跳舞的獅子"; /** 懶加載 只創建一次library對象 */ - (ALAssetsLibrary *)library { if (!_library) { _library = [[ALAssetsLibrary alloc] init]; } return _library; } - (NSString *)groupName { //先從沙盒中取得名字 NSString *groupName = [[NSUserDefaults standardUserDefaults] stringForKey:kGroupNameKey]; if (groupName == nil) {//如果沙盒中取不到這個key(文件夾的名字) groupName = kDefaultGroupName; //儲存名字到沙盒里面 [[NSUserDefaults standardUserDefaults] setObject:groupName forKey:kGroupNameKey]; //synchronize 立馬將上面的key保存到沙盒里面 [[NSUserDefaults standardUserDefaults]synchronize]; } return groupName; } /** 點擊保存按鈕 */ - (IBAction)clickSave:(id)sender { //創建自定義相冊 //獲得文件夾的名字 (調用從沙盒里面取的這個方法) __block NSString *groupName = [self groupName]; //self的弱引用 __weakSelf; //圖片庫 __weak ALAssetsLibrary *weakLibrary = self.library; //創建自定義的相冊 [weakLibrary addAssetsGroupAlbumWithName:groupName resultBlock:^(ALAssetsGroup *group) { if (group) { //新創建的文件夾 //直接把圖片添加到文件夾中 [weakSelf addImageToGroup:group]; }else { //遍歷相冊中的每一個文件 [weakLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) { //取出文件夾的名稱 NSString *name = [group valueForProperty:ALAssetsGroupPropertyName]; if ([name isEqualToString:groupName]) { //如果相等,那么就是自己創建的文件夾 //添加圖片到文件夾中 [weakSelf addImageToGroup:group]; *stop = YES; // 將圖片添加到了文件夾中就停止遍歷 }else if ([name isEqualToString:@"Camera Roll"]) { //文件夾被用戶強制刪除了 (拼接一個空格,就是不同的文件夾的名字) groupName = [groupName stringByAppendingString:@" "]; //儲存新的名字 [[NSUserDefaults standardUserDefaults] setObject:groupName forKey:kGroupNameKey]; [[NSUserDefaults standardUserDefaults]synchronize]; //創建新的文件夾中 [weakLibrary addAssetsGroupAlbumWithName:groupName resultBlock:^(ALAssetsGroup *group) { //添加圖片到文件夾中 [weakSelf addImageToGroup:group]; } failureBlock:nil]; } } failureBlock:nil]; } } failureBlock:nil]; } /** 添加一張圖片到某個文件夾中 */ - (void)addImageToGroup:(ALAssetsGroup *)group { __weak ALAssetsLibrary *weakLibrary = self.library; //需要保存的圖片 CGImageRef image = self.imageView.image.CGImage; //添加圖片到相機膠卷 (因為要先存到全部的相片里面. 在根據對應的assetURL) [weakLibrary writeImageToSavedPhotosAlbum:image metadata:nil completionBlock:^(NSURL *assetURL, NSError *error) { // asset就是一張照片 [weakLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) { //將照片保存到自定的文件夾中 [group addAsset:asset]; [SVProgressHUD showSuccessWithStatus:@"保存成功"]; } failureBlock:nil]; }]; }
Three:
用蘋果iOS推出<Photos/Photos.h> 這個庫
先簡單的介紹下,然后再上代碼
Photos框架須知
1.PHAsset : 一個PHAsset對象代表一張圖片或者一個視頻文件 1> 負責查詢一堆的PHAsset對象 2.PHAssetCollection : 一個PHAssetCollection對象代表一個相冊 1> 負責查詢一堆的PHAssetCollection對象 3.PHAssetChangeRequest 1> 負責執行對PHAsset的【增刪改】操作 2> 這個類只能放在-[PHPhotoLibrary performChanges:completionHandler:] 或者 -[PHPhotoLibrary performChangesAndWait:error:]方法的block中使用 4.PHAssetCollectionChangeRequest 1> 負責執行對PHAssetCollection的【增刪改】操作 2> 這個類只能放在-[PHPhotoLibrary performChanges:completionHandler:] 或者 -[PHPhotoLibrary performChangesAndWait:error:]方法的block中使用 錯誤信息 This method can only be called from inside of -[PHPhotoLibrary performChanges:completionHandler:] or -[PHPhotoLibrary performChangesAndWait:error:] 解決防范 // Asynchronously 異步執行操作 [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ [PHAssetChangeRequest creationRequestForAssetFromImage:self.imageView.image]; } completionHandler:^(BOOL success, NSError * _Nullable error) { JHLog(@"保存完畢") }]; // Synchronously 同步執行操作 NSError *error = nil; [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ [PHAssetChangeRequest creationRequestForAssetFromImage:self.imageView.image]; } error:&error]; // 這個方法只適合加載普通的plist文件,不能用來加載Info.plist [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Test" ofType:@"plist"]]; 安全提示按鈕選擇 // PHAuthorizationStatusNotDetermined // 用戶還沒有對當前App授權過(用戶從未點擊過Don't Allow或者OK按鈕) // PHAuthorizationStatusRestricted // 因為一些系統原因導致無法訪問相冊(比如家長控制) // PHAuthorizationStatusDenied // 用戶已經明顯拒絕過當前App訪問相片數據(用戶已經點擊過Don't Allow按鈕) // PHAuthorizationStatusAuthorized // 用戶已經允許過當前App訪問相片數據(用戶已經點擊過OK按鈕) # 只有遵守了NSFastEnumeration協議的對象才能使用for-in循環
封裝好的代碼,可以根據公司的需求進行修改
我創建新的相冊的名字就是APP的名字,
// 獲取軟件的名字作為相冊的標題
NSString title = [NSBundle mainBundle].infoDictionary[(NSString )kCFBundleNameKey];

定義專屬相冊
#import <Photos/Photos.h> // 在interface中寫方法的聲明,是為了點語法有智能提示 - (PHFetchResult<PHAsset *> *)createdAssets; - (PHAssetCollection *)createdCollection; /** * 獲得剛才添加到【相機膠卷】中的圖片 */ - (PHFetchResult<PHAsset *> *)createdAssets { __block NSString *createdAssetId = nil; // 添加圖片到【相機膠卷】 [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ createdAssetId = [PHAssetChangeRequest creationRequestForAssetFromImage:self.imageView.image].placeholderForCreatedAsset.localIdentifier; } error:nil]; if (createdAssetId == nil) return nil; // 在保存完畢后取出圖片 return [PHAsset fetchAssetsWithLocalIdentifiers:@[createdAssetId] options:nil]; } /** * 獲得【自定義相冊】 */ - (PHAssetCollection *)createdCollection { // 獲取軟件的名字作為相冊的標題 NSString *title = [NSBundle mainBundle].infoDictionary[(NSString *)kCFBundleNameKey]; // 獲得所有的自定義相冊 PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; for (PHAssetCollection *collection in collections) { if ([collection.localizedTitle isEqualToString:title]) { return collection; } } // 代碼執行到這里,說明還沒有自定義相冊 __block NSString *createdCollectionId = nil; // 創建一個新的相冊 [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ createdCollectionId = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:title].placeholderForCreatedAssetCollection.localIdentifier; } error:nil]; if (createdCollectionId == nil) return nil; // 創建完畢后再取出相冊 return [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[createdCollectionId] options:nil].firstObject; } /** * 保存圖片到相冊 */ - (void)saveImageIntoAlbum { // 獲得相片 PHFetchResult<PHAsset *> *createdAssets = self.createdAssets; // 獲得相冊 PHAssetCollection *createdCollection = self.createdCollection; if (createdAssets == nil || createdCollection == nil) { [SVProgressHUD showErrorWithStatus:@"保存失敗!"]; return; } // 將相片添加到相冊 NSError *error = nil; [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ PHAssetCollectionChangeRequest *request = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:createdCollection]; [request insertAssets:createdAssets atIndexes:[NSIndexSet indexSetWithIndex:0]]; } error:&error]; // 保存結果 if (error) { [SVProgressHUD showErrorWithStatus:@"保存失敗!"]; } else { [SVProgressHUD showSuccessWithStatus:@"保存成功!"]; } } - (IBAction)save { /* requestAuthorization方法的功能 1.如果用戶還沒有做過選擇,這個方法就會彈框讓用戶做出選擇 1> 用戶做出選擇以后才會回調block 2.如果用戶之前已經做過選擇,這個方法就不會再彈框,直接回調block,傳遞現在的授權狀態給block */ PHAuthorizationStatus oldStatus = [PHPhotoLibrary authorizationStatus]; [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { dispatch_async(dispatch_get_main_queue(), ^{ switch (status) { case PHAuthorizationStatusAuthorized: { // 保存圖片到相冊 [self saveImageIntoAlbum]; break; } case PHAuthorizationStatusDenied: { if (oldStatus == PHAuthorizationStatusNotDetermined) return; JHLog(@"提醒用戶打開相冊的訪問開關") break; } case PHAuthorizationStatusRestricted: { [SVProgressHUD showErrorWithStatus:@"因系統原因,無法訪問相冊!"]; break; } default: break; } }); }];