2

iOS API Function UIImageWriteToSavedPhotosAlbum takes a selector as one argment:

func UIImageWriteToSavedPhotosAlbum(_ image: UIImage, 
                              _ completionTarget: Any?, 
                              _ completionSelector: Selector?, 
                              _ contextInfo: UnsafeMutableRawPointer?)

https://developer.apple.com/documentation/uikit/1619125-uiimagewritetosavedphotosalbum

However, in swift, when I call this function, the selector never gets recognized:

class Base {
   func save_image(img:UIImage) {
        UIImageWriteToSavedPhotosAlbum(img, self, Selector("image:didFinishSavingWithError:contextInfo:"), nil)
        // I also tried this:
        // UIImageWriteToSavedPhotosAlbum(img, self, #selector(image(_:didFinishSavingWithError:contextInfo:))
    }

   @objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
        print("Photo Saved Successfully")
    }
}

class Child:Base {
}

// This is how I call the save_image function:
let child = Child()
child.save_image()

As you can see, I tried constructing the selector from the signature, and from a string, but neither works. I always get this error in runtime:

'XXX.Child' does not implement methodSignatureForSelector: -- trouble ahead
Unrecognized selector ......

What is happening here? I am wondering if this is because swift doesn't see the method from the Child class, as the method is inherited from Base class?

How can I pass the selector successfully?

Relevant question I have read:

@selector() in Swift?

NeoWang
  • 17,361
  • 24
  • 78
  • 126
  • What's your version of Swift? You should use `#selector()` if you use Swift 3 for instance. Also, here you have the solution (if you use Swift 3): https://stackoverflow.com/questions/41093735/using-contextinfo-unsaferawpointer-in-uiimagewritetosavedphotosalbum-swift-3 – Larme Sep 25 '17 at 15:19
  • @Larme Swift 3. I used `#selector()`, doesn't work either. – NeoWang Sep 25 '17 at 15:26

3 Answers3

11

methodSignatureForSelector is the NSObject's method. So, You need to inherit the NSObject class.

class Base: NSObject {
    ...
}
shtnkgm
  • 1,396
  • 15
  • 17
4

Provide some guidance to your selector to help it find the right function:

class Base {
    func save_image(img:UIImage) {
        UIImageWriteToSavedPhotosAlbum(img, self, #selector(Base.image(_:didFinishSavingWithError:contextInfo:)), nil)
    }

    @objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
        print("Photo Saved Successfully")
    }
}

class Child:Base {
}

// This is how I call the save_image function:
let child = Child()
child.save_image()
CodeBender
  • 35,668
  • 12
  • 125
  • 132
3

After all I have tried, I find that the crucial things are:

  1. method signature must match(a lot of answers have covered that)
  2. do not pass the parameters to the wrong positions, one of my failures is, I passed the target to the contextInfo
  3. maybe in Swift only, the class that implements the the callback function, must be inherited from NSObject
Monsoir
  • 117
  • 1
  • 8
  • 1
    SURELY -> in Swift only, the class that implements the callback function, must be inherited from NSObject – Reimond Hill Oct 27 '20 at 10:25
  • 2
    @ReimondHill yes, you are right, all objects in Objective-C are inherited from `NSObject` , only the objects in Swift have the choices – Monsoir Oct 28 '20 at 02:58
  • Step 3 fixed my problem and it was because I had a Swift class not extending from NSObject. However, I didn't think about adding @objc. Not sure if that will make a difference... – Reimond Hill Oct 28 '20 at 08:58