前言:iOS 保存图片有3种原生API:
使用C函数、AssetsLibrary框架、Photos框架
目前常使用Photos框架,它从 iOS 8 被苹果推出
而AssetsLibrary框架从 iOS 9 开始已被苹果放弃
本文将主要介绍三种方法的使用和注意点
方法一:使用C函数 保存图片(简单)
- 方法名:UIImageWriteToSavedPhotosAlbum
只能保存图片到相册,不能自定义照片分组,使用方便,看需求
// 保存图片
- (IBAction)save:(id)sender {
UIImageWriteToSavedPhotosAlbum(self.imageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{
BQFunc();
if (error) {
[SVProgressHUD showErrorWithStatus:@"保存失败!"];
} else {
[SVProgressHUD showSuccessWithStatus:@"保存成功!"];
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[SVProgressHUD dismiss];
});
}
方法二:AssetsLibrary框架(iOS9开始已过期)
- ALASSetsGroupType: 类型
ALAssetsGroupLibrary//从iTunes来的相册内容(如本身自带的向日葵照片)。
ALAssetsGroupAlbum//设备自身产生或从iTunes同步来的照片,但是不包括照片流跟分享流中的照片。(例如从各个软件中保存下来的图片)ALAssetsGroupEvent相机接口事件产生的相册
ALAssetsGroupFaces//脸部相册(具体不清楚)
ALAssetsGroupSavedPhotos//相机胶卷照片
ALAssetsGroupPhotoStream//照片流
ALAssetsGroupAll//除了ALAssetsGroupLibrary上面所的内容
- AssetsLibrary获取文件夹:
[self.imagePickerController.assetsLibrary enumerateGroupsWithTypes:[typeunsignedIntegerValue]
usingBlock:^(ALAssetsGroup*assetsGroup,BOOL*stop) {
}failureBlock:^(NSError*error) {
NSLog(@"Error: %@", [errorlocalizedDescription]);
}];
- 获取图片:
[self.assetsGroup enumerateAssetsUsingBlock:^(ALAsset*result,NSUIntegerindex,BOOL*stop) {
if(result) {
[assetsaddObject:result];
}
}];
[self.assetsGroup enumerateAssetsAtIndexes:indexes options:0 usingBlock:^(ALAsset*result,NSUIntegerindex,BOOL*stop) {
}];
方法三:Photos框架(重点)
1.Photos框架须知:
1.PHAsset : 一个PHAsset对象就代表相册中的一张图片或者一个视频
1> 查 : [PHAsset fetchAssets...]
2> 增删改 : PHAssetChangeRequest(包括图片\视频相关的所有改动操作)2.PHAssetCollection : 一个PHAssetCollection对象就代表一个相册
1> 查 : [PHAssetCollection fetchAssetCollections...]
2> 增删改 : PHAssetCollectionChangeRequest(包括相册相关的所有改动操作)3.对相片\相册的任何【增删改】操作,都必须放到以下方法的block中执行
-[PHPhotoLibrary performChanges:completionHandler:]
-[PHPhotoLibrary performChangesAndWait:error:]
2.保存图片到相机胶卷:
- 先导入框架:
#import <Photos/Photos.h>
- 异步保存方法:
// 异步执行修改操作
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest creationRequestForAssetFromImage:self.imageView.image];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (error) {
[SVProgressHUD showErrorWithStatus:@"保存失败!"];
} else {
[SVProgressHUD showSuccessWithStatus:@"保存成功!"];
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[SVProgressHUD dismiss];
});
}];
- 同步保存方法:
// 同步执行修改操作
NSError *error = nil;
[[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
[PHAssetChangeRequest creationRequestForAssetFromImage:self.imageView.image];
} error:&error];
if (error) {
[SVProgressHUD showErrorWithStatus:@"保存失败!"];
} else {
[SVProgressHUD showSuccessWithStatus:@"保存成功!"];
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[SVProgressHUD dismiss];
});
3.创建自定义相册:
#pragma mark - 获得当前App对应的自定义相册/保存的图片
/**
获取当前App对应的自定义相册
*/
- (PHAssetCollection *)createdCollection {
NSString *title = [NSBundle mainBundle].infoDictionary[(__bridge NSString *)kCFBundleNameKey]; // 获得app名
PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; //抓取所有的自定义相册
for (PHAssetCollection *collection in collections) { // 遍历查找当前app对应的自定义相册
if ([collection.localizedTitle isEqualToString:title]) { //找到对应的相册:说明已经创建完毕,直接返回
return collection;
}
}
PHAssetCollection *createdCollection = nil;
if (createdCollection == nil){ //自定义相册没被创建过,需要创建自定义相册
NSError *error = nil;
__block NSString *createdCollectionID = nil;
[[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
createdCollectionID = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:title].placeholderForCreatedAssetCollection.localIdentifier; // 创建一个自定义相册,并拿到相册的唯一标识
} error:&error];
if (error) { //如果有值,则创建相册失败,直接返回
return nil;
}
createdCollection = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[createdCollectionID] options:nil].firstObject; //拿到唯一标识后,拿到唯一相册
}
return createdCollection;
}
4.获取保存在相机胶卷的这张图片(通过AssetID)
/**
获取保存在相机胶卷的这张图片(通过AssetID)
*/
- (PHFetchResult<PHAsset *> *)createdAssets {
// 同步执行修改操作
NSError *error = nil;
// 保存图片到相机胶卷
__block NSString *assetID = nil; //相片ID
[[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
assetID = [PHAssetChangeRequest creationRequestForAssetFromImage:self.imageView.image].placeholderForCreatedAsset.localIdentifier; // 赋值ID
} error:&error];
if (error) {
return nil;
}
// 返回相机胶卷里的该相片
return [PHAsset fetchAssetsWithLocalIdentifiers:@[assetID] options:nil];
}
5.保存图片到自定义相册
/**
保存图片到相册
*/
- (void)saveImageIntoAlbum {
// 1.获取相机胶卷里的该【相片】
PHFetchResult<PHAsset *> *createdAssets = self.createdAssets;
if (createdAssets==nil) {
[SVProgressHUD showErrorWithStatus:@"获取相片失败!"];
return;
}
// 2.获得【自定义相册】
PHAssetCollection *createdCollection = self.createdCollection;
if (createdCollection==nil) {
[SVProgressHUD showErrorWithStatus:@"创建/获取相册失败!"];
return;
}
// 3.保存图片到【自定义相册】
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:@"保存成功!"];
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[SVProgressHUD dismiss];
});
}
6.请求和访问相册权限
// save点击事件:保存图片至相册胶卷
- (IBAction)save:(id)sender {
PHAuthorizationStatus oldStatus = [PHPhotoLibrary authorizationStatus];
// 请求/检查访问权限:
// 如果用户还没有做出选择,会自动弹框,用户对弹框做出选择后,才会调用block
// 如果之前已经做过选择,会直接执行block
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
BQLog(@"%zd",status);
dispatch_async(dispatch_get_main_queue(), ^{
if (status == PHAuthorizationStatusDenied && oldStatus != PHAuthorizationStatusNotDetermined) { //用户拒绝当前App访问相册
BQLog(@"提醒用户打开开关");
[SVProgressHUD showErrorWithStatus:@"无系统权限访问"];
} else if (status == PHAuthorizationStatusAuthorized){ // 用户允许当前App访问相册
[self saveImageIntoAlbum];
} else if (status == PHAuthorizationStatusRestricted){ // 无法访问相册
[SVProgressHUD showErrorWithStatus:@"因系统原因,无法访问相册"];
}
});
}];
}
感谢观看,欢迎点赞关注互相交流技术问题~