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
- delete third line of the code
- 删除代码的第三行
- Verify that the _mChangeRequest is __block variable
- 验证_mChangeRequest是__block变量
- compile and run
- 编译并运行
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
- delete third line of the code
- 删除代码的第三行
- Verify that the _mChangeRequest is __block variable
- 验证_mChangeRequest是__block变量
- compile and run
- 编译并运行
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以及用法说明。