美文网首页OC开发逗B的世界你不懂
图片保存到自定义相册

图片保存到自定义相册

作者: 武一顶顶 | 来源:发表于2016-05-26 17:58 被阅读1319次

    保存到自定义相册分3步:

    • 1.添加图片到【相机胶卷】
      1> UIImageWriteToSavedPhotosAlbum函数
      2> AssetsLibrary框架(已过期,一般不用了)
      3> Photos框架(推荐)

    • 2.拥有一个【自定义相册】
      1> AssetsLibrary框架
      2> Photos框架(推荐)

    • 3.将刚才添加到【相机胶卷】的图片,引用(添加)到【自定义相册】
      1> AssetsLibrary框架
      2> Photos框架(推荐)

    Photos框架

    • 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中使用

    • iOS中的 ~增删改查CRUD

    一:保存图片到相册

    
     错误信息
     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) {
        XMGLog(@"保存完毕")
     }];
     
     // Synchronously 同步执行操作
     NSError *error = nil;
     [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
        [PHAssetChangeRequest creationRequestForAssetFromImage:self.imageView.image];
     } error:&error];
    
    

    demo

    
    - (IBAction)save {
        __block NSString *createdAssetId = nil;
        // 添加图片到【相机胶卷】
        // 同步方法,直接创建图片,代码执行完,图片没创建完,所以使用占位ID (createdAssetId)
        [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
            createdAssetId = [PHAssetChangeRequest creationRequestForAssetFromImage:self.imageView.image].placeholderForCreatedAsset.localIdentifier;
        } error:nil];
        
        // 在保存完毕后取出图片
        PHFetchResult<PHAsset *> *createdAssets = [PHAsset fetchAssetsWithLocalIdentifiers:@[createdAssetId] options:nil];
        
        // 获取软件的名字作为相册的标题
        //如果用普通plist文件创建方法创建是错误的,如
    //[NSDictionary dictionaryWithContensOfFile:[[NSBundle mainBundle] pathForResource:@"Test"ofType:@"plist"]];
    // 系统的plist文件只能使用以下方法调用
        NSString *title = [NSBundle mainBundle].infoDictionary[(NSString *)kCFBundleNameKey];
        
        // 已经创建的自定义相册
        PHAssetCollection *createdCollection = nil;
        
        // 获得所有的自定义相册
        PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
        for (PHAssetCollection *collection in collections) {
            if ([collection.localizedTitle isEqualToString:title]) {
                createdCollection = collection;
                break;
            }
        }
    
        if (!createdCollection) { // 没有创建过相册
            __block NSString *createdCollectionId = nil;
            // 创建一个新的相册
            [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
                createdCollectionId = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:title].placeholderForCreatedAssetCollection.localIdentifier;
            } error:nil];
            
            // 创建完毕后再取出相册
            createdCollection = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[createdCollectionId] options:nil].firstObject;
        }
        
        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:@"保存成功!"];
        }
    }
    

    封装与授权

    /**
     *  获得刚才添加到【相机胶卷】中的图片
     */
    - (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) {
            //涉及到UI弹框 GCD到主线程
            dispatch_async(dispatch_get_main_queue(), ^{
                switch (status) {
                    case PHAuthorizationStatusAuthorized: {
                        //  保存图片到相册
                        [self saveImageIntoAlbum];
                        break;
                    }
                        
                    case PHAuthorizationStatusDenied: {
                        if (oldStatus == PHAuthorizationStatusNotDetermined) return;
                        
                        XMGLog(@"提醒用户打开相册的访问开关")
                        break;
                    }
                        
                    case PHAuthorizationStatusRestricted: {
                        [SVProgressHUD showErrorWithStatus:@"因系统原因,无法访问相册!"];
                        break;
                    }
                        
                    default:
                        break;
                }
            });
        }];
        
        // PHAuthorizationStatusNotDetermined
        // 用户还没有对当前App授权过(用户从未点击过Don't Allow或者OK按钮)
        
        // PHAuthorizationStatusRestricted
        // 因为一些系统原因导致无法访问相册(比如家长控制)
        
        // PHAuthorizationStatusDenied
        // 用户已经明显拒绝过当前App访问相片数据(用户已经点击过Don't Allow按钮)
        
        // PHAuthorizationStatusAuthorized
        // 用户已经允许过当前App访问相片数据(用户已经点击过OK按钮)
        
    //    switch ([PHPhotoLibrary authorizationStatus]) {
    //        case PHAuthorizationStatusAuthorized: {
    //            [self saveImageIntoAlbum];
    //            break;
    //        }
    //        
    //        case PHAuthorizationStatusDenied: {
    //            // 提醒用户打开访问开关
    //            break;
    //        }
    //            
    //        case PHAuthorizationStatusRestricted: {
    //            [SVProgressHUD showErrorWithStatus:@"因系统原因,无法访问相册!"];
    //            break;
    //        }
    //            
    //        case PHAuthorizationStatusNotDetermined: {
    //            // 弹框让用户做出选择
    //            [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
    //                // 用户刚才点击的是OK按钮
    //                if (status == PHAuthorizationStatusAuthorized) {
    //                    [self saveImageIntoAlbum];
    //                }
    //            }];
    //            break;
    //        }
    //    }
    }
    
    /*
     PHPhotoLibrary的performChangesAndWait的block不能嵌套,比如下面的写法是错误的
     [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
        [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
     
        } error:nil];
     } error:nil];
     */
    @end
    

    相关文章

      网友评论

      • Maj_sunshine:Domain=NSCocoaErrorDomain Code=-1 为什么会返回这个error
        Maj_sunshine:跳到保存成功的block中但实际没保存:persevere:
      • 一本大书:动态图片保存后变为静态!!
      • 一本大书:赞一个!
      • 小白哥_29984:返回值不是 createdAssetId
        Chipmuck:@小白哥_29984 localIdentifier的类型是NSString 是对的。
      • 小白哥_29984: createdAssetId = [PHAssetChangeRequest creationRequestForAssetFromImage:self.imageView.image].placeholderForCreatedAsset.localIdentifier;
        这不对

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

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