美文网首页iOS 开发每天分享优质文章iOS 开发
iOS 保存图片到【自定义相册】

iOS 保存图片到【自定义相册】

作者: IIronMan | 来源:发表于2019-06-16 11:37 被阅读12次

    一、保存图片到自定义相册的三个步骤

    • 1.保存图片到相册【相机胶卷】
      1>、C语言保存
      2>、#import <AssetsLibrary/AssetsLibrary.h> 保存

      AssetsLibrary框架: iOS9 之后开始被废弃

      3>、#import <Photos/Photos.h> 保存

      Photos框架 iOS 8 开始就可以用了

    • 2.拥有一个自定义相册:使用AssetsLibraryPhotos框架

    • 3.将刚才保存到【相机胶卷中的图片】引用到【自定义的相册】:使用AssetsLibraryPhotos框架

    二、单纯的C语言保存图片到相册(不使用AssetsLibraryPhotos框架)

    • 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 框架基本认识,我们可以在 Help->Developer Documentation-> 选择OC或者Swift 搜索 Photos

      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";
      
    • 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对象];
        效果图

    相关文章

      网友评论

        本文标题:iOS 保存图片到【自定义相册】

        本文链接:https://www.haomeiwen.com/subject/rfxbfctx.html