iOS 保存图片到【自定义相册】
一、保存图片到自定义相册的三个步骤
-
1.保存图片到相册【相机胶卷】
1>、C语言保存
2>、#import <AssetsLibrary/AssetsLibrary.h> 保存AssetsLibrary框架: iOS9 之后开始被废弃
3>、#import <Photos/Photos.h> 保存
Photos框架 iOS 8 开始就可以用了
-
2.拥有一个自定义相册:使用
AssetsLibrary
与Photos
框架 -
3.将刚才保存到【相机胶卷中的图片】引用到【自定义的相册】:使用
AssetsLibrary
与Photos
框架
二、单纯的C语言保存图片到相册(不使用AssetsLibrary
与Photos
框架)
-
2.1、保存图片到相册
/** <#Description#> 第1个参数:UIIMage 对象 第2个参数:监听对象 第3个参数:保存后所走【监听对象】的方法 第4个参数:描述文字,一般为 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(@"保存成功"); } }
提示:上面第三个参数是要按照苹果的格式来写方法名的,点击方法进去 我们可以到如下代码:
// 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;
苹果让我们按照他们的格式来写方法,我们可以把他们的方法名替换为任意的名字,如:- (void)a:(UIImage *)image b:(NSError *)error c:(void *)contextInfo;
三、Photos 框架
-
3.1、Photos 框架基本认识,我们可以在
Photos 框架检索Help
->Developer Documentation
-> 选择OC或者Swift 搜索Photos
Photos 是用来处理 视频 与 图片 的,下面是其主要的类-
<1>、
PHAsset
:一个 PHAsset 对象就代表相册中的一张图片或者一个视频(1)、查:[PHAsset fetch.....]
(2)、增删改:PHAssetChangeRequest,改变图片 (包括 图片/视频 相关的所有改动操作) -
<2>、:
PHAssetCollection
: 一个PHAssetCollection就代表一个相册
(1)、查:[PHAssetCollection fetch.....]
(2)、增删改:PHAssetCollectionChangeRequest,改变相册 (包括 相册 相关的所有改动操作)
提示:所有的增删改的操作都要放到:
-[PHPhotoLibrary performChanges:completionHandler:] or -[PHPhotoLibrary performChangesAndWait:error:]'
方法里面 -
-
3.2、使用 Photos 框架保存图片到【相机胶卷】
-
异步操作保存到相册
[[PHPhotoLibrary sharedPhotoLibrary]performChanges:^{ [PHAssetChangeRequest creationRequestForAssetFromImage:self.photoimageView.image]; } completionHandler:^(BOOL success, NSError * _Nullable error) { if (error) { [SVProgressHUD showErrorWithStatus:@"保存失败"]; }else{ [SVProgressHUD showErrorWithStatus:@"保存成功"]; } }];
-
同步操作保存到相册
NSError *error = nil; [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ [PHAssetChangeRequest creationRequestForAssetFromImage:self.photoimageView.image]; } error:&error]; if (error) { [SVProgressHUD showErrorWithStatus:@"保存失败"]; }else{ [SVProgressHUD showErrorWithStatus:@"保存成功"]; }
提示:使用 Photos 框架保存图片到【相机胶卷】必须把代码放到上面的两个方法里面,否则会报下面的错
reason: 'This method can only be called from inside of -[PHPhotoLibrary performChanges:completionHandler:] or -[PHPhotoLibrary performChangesAndWait:error:]'
-
-
3.3、创建新的相册(自定义一个属于自己app的相册),提示:创建相册之前要先判断相册是否存在,存在就不再创建
NSError *error = nil; [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ // 获取app的名字 NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; // 创建一个自定义的相册 [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle: appName]; } error:&error]; if (error) { [SVProgressHUD showErrorWithStatus:@"创建相册失败"]; }else{ [SVProgressHUD showErrorWithStatus:@"创建相册成功"]; }
提示一:
kCFBundleNameKey = @"CFBundleName"
,下面的两句是一个意思- NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
下面是:C 的strting转为NSString - NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleNameKey];
提示二:Foundation 和 Core Foundation 的数据类型可以相互转换,比如:NSString * 和 CFStringRef,如下面的例子:
NSString *string = (NSString *)kCFBundleNameKey; CFStringRef string = (CFStringRef)@"name";
- NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
-
3.4、查询相册 (自定义相册或者系统相册)
/** PHAssetCollectionTypeAlbum = 1, 自定义相册(普通的相册) PHAssetCollectionTypeSmartAlbum = 2, 智能相册(系统自带的相册),如:Camera Roll PHAssetCollectionTypeMoment = 3, 按照时刻分的相册 */ // 相机胶卷相册,打印:Camera Roll // PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil]; // 自定义相册,打印:自定义相册的名字 PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; for (PHAssetCollection *collection in collections) { NSLog(@"相册的名字=%@",collection.localizedTitle); }
-
3.5.创建相册与查询相册合在一起,如下
// 获取app的名字 NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; /** PHAssetCollectionTypeAlbum = 1, 自定义相册(普通的相册) PHAssetCollectionTypeSmartAlbum = 2, 智能相册(系统自带的相册),如:Camera Roll PHAssetCollectionTypeMoment = 3, 按照时刻分的相册 */ // 相机胶卷相册,打印:Camera Roll // PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil]; // 自定义相册,打印:自定义相册的名字 PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; // 自己的相册 PHAssetCollection *appCollection = nil; for (PHAssetCollection *collection in collections) { NSLog(@"相册的名字=%@",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"]; // 获取相册的唯一标识符 createCollectionID = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:appName].placeholderForCreatedAssetCollection.localIdentifier; } error:&error]; if (error) { [SVProgressHUD showErrorWithStatus:@"创建相册失败"]; }else{ appCollection = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[createCollectionID] options:nil].firstObject; [SVProgressHUD showErrorWithStatus:@"创建相册成功"]; } } // 相册一定存在 NSLog(@"相册已经存在");
提示:这里有一个技术点就是:根据创建相册返回的相册唯一标识符获取相册对象,如下代码:
// 自己的相册 PHAssetCollection *appCollection = nil; if (appCollection == nil) { NSError *error = nil; __block NSString *createCollectionID = nil; [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ // 获取app的名字 NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; // 获取相册的唯一标识符 createCollectionID = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:appName].placeholderForCreatedAssetCollection.localIdentifier; } error:&error]; if (error) { [SVProgressHUD showErrorWithStatus:@"创建相册失败"]; }else{ appCollection = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[createCollectionID] options:nil].firstObject; [SVProgressHUD showErrorWithStatus:@"创建相册成功"]; } }
- 再次提示:只有上面的block代码执行完才代表相册可能存在,所以,获取PHAssetCollection放在了下面
-
3.6、保存图片到自定义的相册
-(void)savePhotosToAppPhotoCollection{ // 同步操作保存到【相机胶卷】 __block PHObjectPlaceholder *placeholderForCreatedAsset; NSError *error = nil; [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ placeholderForCreatedAsset = [PHAssetChangeRequest creationRequestForAssetFromImage:self.photoimageView.image].placeholderForCreatedAsset; } error:&error]; if (error) { [SVProgressHUD showErrorWithStatus:@"保存图片失败"]; return; } // 获得自定义相册 PHAssetCollection *createCollection = [JKPhotosKit createPHAssetCollection]; if (createCollection == nil) { [SVProgressHUD showErrorWithStatus:@"创建相册失败"]; return; } // 添加刚才保存的图片到 【自定义相册】 [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ // 获取自定义对象的操作对象 PHAssetCollectionChangeRequest *request = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:createCollection]; // 把图片插入到自定义相册的第一个位置 [request insertAssets:@[placeholderForCreatedAsset] atIndexes:[NSIndexSet indexSetWithIndex:0]]; } error:&error]; if (error) { [SVProgressHUD showErrorWithStatus:@"保存图片失败"]; }else{ [SVProgressHUD showSuccessWithStatus:@"保存图片成功"]; } }
-
3.7、用户相册权限的判断
// 请求或者访问用户访问权限: // 如果还没有做出选择,会自动弹框,用户对弹框做出选择后才会调用block; // 如果用户之前已经做出过选择,会自动执行block /** PHAuthorizationStatusNotDetermined = 0,还没决定 PHAuthorizationStatusRestricted = 1,没有授权,不能访问用户相册 PHAuthorizationStatusDenied = 2,用户拒绝这个应用 PHAuthorizationStatusAuthorized = 3 用户授权这个app访问这个相册 */ // 获取用户之前的状态 PHAuthorizationStatus oldStatus = [PHPhotoLibrary authorizationStatus]; [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { // 用户决绝当前 App 访问相册 dispatch_async(dispatch_get_main_queue(), ^{ if (status == PHAuthorizationStatusDenied) { if (oldStatus != PHAuthorizationStatusDenied) { // 提醒用户打开开关 }else{ } }else if (status == PHAuthorizationStatusAuthorized){ // 用户允许当前 App 访问相册 [self trueSaveImageToAppPhotoCollection:saveImage]; }else if (status == PHAuthorizationStatusRestricted){ // 因系统原因无法访问相册 [SVProgressHUD showErrorWithStatus:@"因系统原因无法访问相册"]; } }); }];
提示:上面所有的完整代码都在
JKPhotosKit
类里面,需要的请下载 demo- JKPhotosKit 类的使用方法:保存图片到自定的相册
[JKPhotosKit savePhotosToAppPhotoCollection:UIImage对象
];
效果图
- JKPhotosKit 类的使用方法:保存图片到自定的相册