8

Trying hard to get UIImageWriteToSavedPhotosAlbum to work in swift https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/index.html#//apple_ref/c/func/UIImageWriteToSavedPhotosAlbum

The documentation is sadly ONLY in objective C.

Here is my code:

func saveImage()
{
  UIImageWriteToSavedPhotosAlbum(uiimage, self, "saveImageComplete:::", nil)
}

func saveImageComplete(image:UIImage,err:NSError,context:UnsafePointer<()>)
{
  loadLastPhotoIntoGalleryIcon()
}

But the problem is that it throws the NSInvalidArgumentException with an unrecognized selector:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', 
reason: 'app.PhotoEditor<0x14a1e400> does not respond to selector 
saveImageComplete:::'

Can you advise what is wrong with my syntax and how I properly specific this selector? From what I understand, each : represents 1 argument the method expects and since it has 3 parameters I gave it 3 :'s.

Thanks!

Aggressor
  • 13,323
  • 24
  • 103
  • 182
  • Possible duplicate: [@selector() in Swift?](http://stackoverflow.com/q/24007650/643383) – Caleb Dec 09 '14 at 19:53
  • I upvoted that answer months ago, its failing for my method with multiple paramters – Aggressor Dec 09 '14 at 19:55
  • As in if I have a method with only 1 paramters and I do "methodName:" that works just fine. The second I go over 1, I run into issues – Aggressor Dec 09 '14 at 19:56
  • If your method were an Objective-C method, the selector would be something like "saveImageCompleteImage:err:context:". You can't just leave out parts of the name. – Caleb Dec 09 '14 at 19:56
  • That is NOT true you can specific parameters with : only. http://stackoverflow.com/questions/722651/how-do-i-pass-multiple-parameters-in-objective-c – Aggressor Dec 09 '14 at 20:01
  • 1
    Yes, you *can* do that in Obj-C, but you didn't. What I'm trying to point out is that the name of your function doesn't map to a selector `"saveImageComplete:::"`, but is closer to what I suggested. IOW, given the name that you chose for your function, the selector you're using is incorrect. And that's pretty much what the error message you're getting is telling you, too. – Caleb Dec 09 '14 at 20:10
  • 1
    Now if you put that as an answer I can accept that! saveImageCompleteimage:err:context: worked! I did not know that Swift did not carry the same logic of paramter spefication – Aggressor Dec 09 '14 at 20:13
  • Try making the callback public. – Zdeněk Topič Dec 09 '14 at 20:17

6 Answers6

14

Above none work for Swift3. Try this for those who are struggling with Swift3 Syntax's

Action:

@IBAction func saveToPhotos(_ sender: AnyObject) {

    UIImageWriteToSavedPhotosAlbum(yourImageView.image!, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
}

Target:

func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {

    if error == nil {
        let ac = UIAlertController(title: "Saved!", message: "Image saved to your photos.", preferredStyle: .alert)
        ac.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        present(ac, animated: true, completion: nil)
    } else {
        let ac = UIAlertController(title: "Save error", message: error?.localizedDescription, preferredStyle: .alert)
        ac.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        present(ac, animated: true, completion: nil)
    }
}

Refer this link for more clarification https://www.hackingwithswift.com/read/13/5/saving-to-the-ios-photo-library

Sanju
  • 1,148
  • 11
  • 26
6

The correct UIImageWriteToSavedPhotosAlbum/selector code is here:

func onYesClicked(action:Int){
    // i'm using optional image here just for example
    if let image = getImage() {
        UIImageWriteToSavedPhotosAlbum(
            image, self,
            Selector("image:didFinishSavingWithError:contextInfo:"),
            nil)
    }
}

func image(
    image: UIImage!,
    didFinishSavingWithError error:NSError!,
    contextInfo:UnsafePointer<Void>)
{
    // process success/failure here
}

Here's the most up-to-date syntax, 2016

@IBAction func clickedSaveToUsersCameraRoll()
    {
    print("actually saving yourImage.image to the camera roll, 2016.")
    UIImageWriteToSavedPhotosAlbum(
        yourImage.image!, self,
        #selector(savedOK(_:didFinishSavingWithError:contextInfo:)),
        nil)
    }

func savedOK(
        image:UIImage!,
        didFinishSavingWithError error:NSError!,
        contextInfo:UnsafePointer<Void>)
    {
    print("Wrote photo ok")
    }
Fattie
  • 27,874
  • 70
  • 431
  • 719
Anthony Akentiev
  • 1,001
  • 11
  • 9
4

If your method were an Objective-C method, the selector would be something like "saveImageCompleteImage:err:context:". You need to remember that the parameters are part of the name in Objective-C, so "saveImageComplete:::" doesn't specify a method that could be called saveImageComplete(image:UIImage,err:NSError,context:UnsafePointer<()>) in Swift.

Caleb
  • 124,013
  • 19
  • 183
  • 272
  • This is correct. I mistakenly thought the logic of specifying parameters with : carried over from Objc, changing to the full name of the method "saveImageComplete:err:context:" (you can leave out the first parameter) works. The reason for confusion is just that, swift allows you to leave out the first paramter with a : but the others must be explicity stated in the string! – Aggressor Dec 09 '14 at 20:21
3

In Swift 4.x and 5.0:

UIImageWriteToSavedPhotosAlbum(imageToSave, self, #selector(saveImageComplete(image:err:context:)), nil)

Don't forget the @objc decorator in it's declaration:

@objc private func saveImageComplete(image:UIImage, err:NSError, context:UnsafeMutableRawPointer?) {
    
}
wzso
  • 3,482
  • 5
  • 27
  • 48
1

You can do this by calling single line of code also

   UIImageWriteToSavedPhotosAlbum(imageToSave!,self,nil,nil)
Uma Madhavi
  • 4,851
  • 5
  • 38
  • 73
Anny
  • 509
  • 1
  • 5
  • 14
0

try swift 4.x+

class ImageSaver: NSObject {
    func writeToPhotoAlbum(image: UIImage) {
        UIImageWriteToSavedPhotosAlbum(image, self, #selector(saveError), nil)
    }

    @objc func saveError(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
        print("Save finished!")
    }
}
Lam Nguyen
  • 565
  • 1
  • 5
  • 7