使用照片框架将图像保存到照片库

时间:2022-11-14 13:17:47

My app crashes every time when I try to save image using photo framework.

每当我尝试使用照片框架保存图像时,我的应用程序都会崩溃。

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{

      _mChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:[info valueForKey:UIImagePickerControllerOriginalImage]];

      [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{

      _mChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:[info valueForKey:UIImagePickerControllerOriginalImage]];

      } completionHandler:^(BOOL success, NSError *error) {

          if (success) {

              PHObjectPlaceholder *assetPlaceholder = _mChangeRequest.placeholderForCreatedAsset;
          }
          else {

             NSLog(@"write error : %@",error);
          }
    }];
}

crash : NSInternalInconsistencyException', reason: 'This method can only be called from inside of -[PHPhotoLibrary performChanges:completionHandler:] or -[PHPhotoLibrary performChangesAndWait:error:]'

4 个解决方案

#1


34  

All you need to do is trigger a creation request. As the error says, you can access the change request only inside the performChanges block.

您需要做的就是触发创建请求。如错误所示,您只能在performChanges块内访问更改请求。

So to save the image you would do something like this:

因此,要保存图像,您可以执行以下操作:

[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
    [PHAssetChangeRequest creationRequestForAssetFromImage:[info valueForKey:UIImagePickerControllerOriginalImage]];
} completionHandler:^(BOOL success, NSError *error) {
    if (success) {
         NSLog(@"Success");
    }
    else {
        NSLog(@"write error : %@",error);
    }
}];

In case you need to do something with the placeholder of the newly created asset, you can access it inside the same performChanges block:

如果您需要对新创建的资产的占位符执行某些操作,则可以在同一performChanges块中访问它:

PHAssetChangeRequest *changeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:[info valueForKey:UIImagePickerControllerOriginalImage]];
PHObjectPlaceholder *assetPlaceholder = changeRequest.placeholderForCreatedAsset;

#2


2  

  1. delete third line of the code
  2. 删除代码的第三行
  3. Verify that the _mChangeRequest is __block variable
  4. 验证_mChangeRequest是__block变量
  5. compile and run
  6. 编译并运行

you will see that image in the photos app

你会在照片应用程序中看到该图像

you will change code probably like this...

你可能会像这样改变代码......

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{

  __block PHAssetChangeRequest *_mChangeRequest = nil;

  [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{

  _mChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:[info valueForKey:UIImagePickerControllerOriginalImage]];

  } completionHandler:^(BOOL success, NSError *error) {

      if (success) {

          PHObjectPlaceholder *assetPlaceholder = _mChangeRequest.placeholderForCreatedAsset;
      }
      else {

         NSLog(@"write error : %@",error);
      }
}];
}

#3


2  

In Swift 3 I do this to save the video to the library.

在Swift 3中,我这样做是为了将视频保存到库中。

        if mediaType.isEqual(to: (kUTTypeMovie as NSString) as String) {
            if let videoURL = info[UIImagePickerControllerMediaURL] as? URL {

            PHPhotoLibrary.shared().performChanges({
                _ = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL)
            }, completionHandler: { (success, error) in
                if success {
                    print("ok")
                    let videoData = NSData(contentsOf: videoURL)
                    // use videoData here if needed...
                    if let posterImage = self.firstFrame(videoURL: videoURL) {
                        self.imageView.image = posterImage
                    }
                    picker.dismiss(animated: true) { () -> Void in

                    }
                }
                else {
                    print(error?.localizedDescription)
                }
            })
        }
    }

#4


2  

Here is an example of code how you can write/save image to Photo Library using UIImageWriteToSavedPhotosAlbum function:

下面是一个代码示例,您可以使用UIImageWriteToSavedPhotosAlbum函数将图像写入/保存到照片库:

- (void)saveImage:(UIImage *)image {
    UIImageWriteToSavedPhotosAlbum(self.image, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;
{
    if (!error) {
        // saved successfully

        PHFetchOptions *fetchOptions = [PHFetchOptions new];
        fetchOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
        PHAsset *asset = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:fetchOptions].firstObject;
        if (asset != nil) {
            // here you can use asset of your image
        }
    } else {
        NSLog(@"save image error: %@", error);
    }
}

Don't forget to add into your Info.plist a key-value pair Privacy - Camera Usage Description with description of usage.

不要忘记在Info.plist中添加一个键值对Privacy - Camera Usage Description以及用法说明。

#1


34  

All you need to do is trigger a creation request. As the error says, you can access the change request only inside the performChanges block.

您需要做的就是触发创建请求。如错误所示,您只能在performChanges块内访问更改请求。

So to save the image you would do something like this:

因此,要保存图像,您可以执行以下操作:

[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
    [PHAssetChangeRequest creationRequestForAssetFromImage:[info valueForKey:UIImagePickerControllerOriginalImage]];
} completionHandler:^(BOOL success, NSError *error) {
    if (success) {
         NSLog(@"Success");
    }
    else {
        NSLog(@"write error : %@",error);
    }
}];

In case you need to do something with the placeholder of the newly created asset, you can access it inside the same performChanges block:

如果您需要对新创建的资产的占位符执行某些操作,则可以在同一performChanges块中访问它:

PHAssetChangeRequest *changeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:[info valueForKey:UIImagePickerControllerOriginalImage]];
PHObjectPlaceholder *assetPlaceholder = changeRequest.placeholderForCreatedAsset;

#2


2  

  1. delete third line of the code
  2. 删除代码的第三行
  3. Verify that the _mChangeRequest is __block variable
  4. 验证_mChangeRequest是__block变量
  5. compile and run
  6. 编译并运行

you will see that image in the photos app

你会在照片应用程序中看到该图像

you will change code probably like this...

你可能会像这样改变代码......

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{

  __block PHAssetChangeRequest *_mChangeRequest = nil;

  [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{

  _mChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:[info valueForKey:UIImagePickerControllerOriginalImage]];

  } completionHandler:^(BOOL success, NSError *error) {

      if (success) {

          PHObjectPlaceholder *assetPlaceholder = _mChangeRequest.placeholderForCreatedAsset;
      }
      else {

         NSLog(@"write error : %@",error);
      }
}];
}

#3


2  

In Swift 3 I do this to save the video to the library.

在Swift 3中,我这样做是为了将视频保存到库中。

        if mediaType.isEqual(to: (kUTTypeMovie as NSString) as String) {
            if let videoURL = info[UIImagePickerControllerMediaURL] as? URL {

            PHPhotoLibrary.shared().performChanges({
                _ = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoURL)
            }, completionHandler: { (success, error) in
                if success {
                    print("ok")
                    let videoData = NSData(contentsOf: videoURL)
                    // use videoData here if needed...
                    if let posterImage = self.firstFrame(videoURL: videoURL) {
                        self.imageView.image = posterImage
                    }
                    picker.dismiss(animated: true) { () -> Void in

                    }
                }
                else {
                    print(error?.localizedDescription)
                }
            })
        }
    }

#4


2  

Here is an example of code how you can write/save image to Photo Library using UIImageWriteToSavedPhotosAlbum function:

下面是一个代码示例,您可以使用UIImageWriteToSavedPhotosAlbum函数将图像写入/保存到照片库:

- (void)saveImage:(UIImage *)image {
    UIImageWriteToSavedPhotosAlbum(self.image, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;
{
    if (!error) {
        // saved successfully

        PHFetchOptions *fetchOptions = [PHFetchOptions new];
        fetchOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
        PHAsset *asset = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:fetchOptions].firstObject;
        if (asset != nil) {
            // here you can use asset of your image
        }
    } else {
        NSLog(@"save image error: %@", error);
    }
}

Don't forget to add into your Info.plist a key-value pair Privacy - Camera Usage Description with description of usage.

不要忘记在Info.plist中添加一个键值对Privacy - Camera Usage Description以及用法说明。