Using completionSelector and completionTarget with UIImageWriteToSavedPhotosAlbum
import UIKit
class ViewController: UIViewController {
@IBAction func buttonPressed(sender: AnyObject) {
presentImagePickerController()
}
}
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func presentImagePickerController() {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
imagePickerController.sourceType = .PhotoLibrary
imagePickerController.allowsEditing = false
presentViewController(imagePickerController, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
UIImageWriteToSavedPhotosAlbum(image, self, "image:didFinishSavingWithError:contextInfo:", nil)
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
self.dismissViewControllerAnimated(true, completion: nil)
}
func image(image: UIImage, didFinishSavingWithError error: NSError?, contextInfo:UnsafePointer<Void>) {
guard error == nil else {
//Error saving image
return
}
//Image saved successfully
}
}
iOS - UIImageWriteToSavedPhotosAlbum
- The
completionSelector
is the selector (method) to call when the writing of the image has finished. - The
completionTarget
is the object on which to call this method.
Generally:
- Either you don't need to be notified when the writing of the image is finished (in many cases that's not useful), so you use
nil
for both parameters - Or you really want to be notified when the image file has been written to the photo album (or ended up with a writing error), and in such case, you generally implement the callback (= the method to call on completion) in the same class that you called the
UIImageWriteToSavedPhotosAlbum
function from, so thecompletionTarget
will generally beself
As the documentation states, the completionSelector
is a selector representing a method with the signature described in the documentation, so it has to have a signature like:
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo: (void *) contextInfo;
It does not have to have this exact name, but it has to use the same signature, namely take 3 parameters (the first being an UIImage
, the second an NSError
and the third being of void*
type) and return nothing (void
).
Example
You may for example declare and implement a method that you could call anything like this :
- (void)thisImage:(UIImage *)image hasBeenSavedInPhotoAlbumWithError:(NSError *)error usingContextInfo:(void*)ctxInfo {
if (error) {
// Do anything needed to handle the error or display it to the user
} else {
// .... do anything you want here to handle
// .... when the image has been saved in the photo album
}
}
And when you call UIImageWriteToSavedPhotosAlbum
you will use it like this:
UIImageWriteToSavedPhotosAlbum(theImage,
self, // send the message to 'self' when calling the callback
@selector(thisImage:hasBeenSavedInPhotoAlbumWithError:usingContextInfo:), // the selector to tell the method to call on completion
NULL); // you generally won't need a contextInfo here
Note the multiple ':' in the @selector(...)
syntax. The colons are part of the method name so don't forget to add these ':' in the @selector (event the trainling one) when you write this line!
which is best to save image in the photo library?
UIImageWriteToSavedPhotosAlbum
should be faster but anyway, you should and you have to do it on a background thread to not block the main thread and the UI.
Somehow like
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImageWriteToSavedPhotosAlbum(img.image, nil, nil, nil);
});
How to use static functions to call UIImageWriteToSavedPhotosAlbum() with completion handler?
What you'd need to do is to set the target to YourClassName.self
.
I.e.,
UIImageWriteToSavedPhotosAlbum(someImage, YourClassName.self, "saveImage:didFinishSavingWithError:contextInfo:", nil)
By the way, your function name is not correct:
//Note the space between saveImage and completionSelector
static func saveImage completionSelector(image: UIImage, didFinishSavingWithError error: NSError?, contextInfo:UnsafePointer<Void>)
I think it should be:
static func saveImageWithCompletionSelector(image: UIImage, didFinishSavingWithError error: NSError?, contextInfo:UnsafePointer<Void>)
Thus, we may need to make a corresponding change:
UIImageWriteToSavedPhotosAlbum(someImage, YourClassName.self, "saveImageWithCompletionSelector:didFinishSavingWithError:contextInfo:", nil)
I just ran a quick test with the aforementioned change and suggestion; there should be a pop-up requesting for authorization for accessing photo album.
How to save picture to iPhone photo library?
You can use this function:
UIImageWriteToSavedPhotosAlbum(UIImage *image,
id completionTarget,
SEL completionSelector,
void *contextInfo);
You only need completionTarget, completionSelector and contextInfo if you want to be notified when the UIImage
is done saving, otherwise you can pass in nil
.
See the official documentation for UIImageWriteToSavedPhotosAlbum()
.
Add image to photo library from bundle when purchased
Call UIImageWriteToSavedPhotosAlbum , which I believe looks like this:
UIImageWriteToSavedPhotosAlbum(
UIImage* image,
id completionTarget,
SEL completionSelector,
void* contextInfo
);
One way to use it is like this:
UIImage* myImage = [UIImage imageNamed:@"image.png"];
UIImageWriteToSavedPhotosAlbum(myImage, self, @selector(image:didFinishSavingWithError:contextInfo), nil);
You only need to set the completion target and completion selector if you want to be notified if it succeeded or failed. If so, don't forget to add this method to the class:
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void*)contextInfo
{
if (error)
{
// Do something on error... (like show a UIAlert for example)
}
else
{
// Do something on success... (maybe show a "Your image was saved" alert
}
}
The image doesn't save right away and might error in the process so this can be useful.
You can also use the ALAssetsLibrary, which I believe would look like this:
ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum:[myImage CGImage] orientation:(ALAssetOrientation)[myImage imageOrientation] completionBlock:^(NSURL* assetURL, NSError* error)
{
if (error)
{
// Do something on error... (like show a UIAlert for example)
}
else
{
// Do something on success... (maybe show a "Your image was saved" alert
}
}];
Hope this helped.
Related Topics
Swift, Google Map Fit Bound for All the Markers
Fbsdkcorekit.Framework/Fbsdkcorekit: No Matching Architecture in Universal Wrapper
iOS with Parse. Pfuser.Currentuser() Not Getting Cached. Returns Nil After App Restart
My Uiviews Muck-Up When I Combine Uipangesturerecognizer and Autolayout
How to Retrieve Image Stored in Firebase to Show It in View Image View
iOS Swift No Such File or Directory in Debug-Iphoneos
Libmobilegestalt Mobilegestalt.C:890: Mgisdeviceoneoftype Is Not Supported on This Platform
Adding Uigesturerecognizer to Subview Programmatically in Swift
Swift - Using Cgcontext to Draw with Finger
How to Unwrap the Elements of an Array in Swift? (Ie. Array<Int> as Array<Int>)
How to Use Multiple Protocols in Swift with Same Protocol Variables
Return in Function Without Return Value in Swift
Incorrect Position of Cashapelayer
Why Sending Message from Watchkit Extension to iOS and Getting Back a Reply Is So Slow