iosswiftsirishortcutsswift5swift-keypath

INIntent `setImage` make runtime crash in Swift 5


I've used INIntent object since Siri shortcut is added. For that I made an intent definition and it generated a INIntent object automatically.

@available(iOS 12.0, watchOS 5.0, *)
@objc(SpotConditionIntent)
public class SpotConditionIntent: INIntent {

    @NSManaged public var spotId: String?
    @NSManaged public var spotName: String?

}

To customize the Siri shortcut voice record screen, I added a convenience initializer. It was basically to add suggestedInvocationPhrase and the top icon image.

@available(iOS 12, *)
extension SpotConditionIntent {
    convenience init(spotId: String, spotName: String) {
        self.init()
        self.spotId = spotId
        self.spotName = spotName
        self.suggestedInvocationPhrase = "\(NSLocalizedString("how_are_waves_text", comment: "How are the waves at")) \(spotName)?"
        if let uiimage = UIImage(named: "check-surf-icon"), let data = uiimage.pngData() {
            let inImage = INImage(imageData: data)
            setImage(inImage, forParameterNamed: \.spotName)
        }
    }
}

Today, I tried to convert the entire project to Swift 5 and there was no issue on building. (There was no actual change in the code.) However it crashes on runtime with very weird message.

Thread 1: Fatal error: could not detangle key path type from XXXX9SpotConditionIntentCXD

and it pointed the setImage(inImage, forParameterNamed: \.spotName).

I just found that the setImage(,forParameterNamed) doesn't exist in the documentation.

enter image description here

https://developer.apple.com/documentation/sirikit/inintent

Seems like I need to use func keyImage() -> INImage? which is added in iOS 12.

But I have no idea why it works in Swift 4.X and can't find any documentation for the deprecation. Anyone knows about this issue?


Solution

  • As far as I checked...

    The two methods are available in Objective-C.

    - imageForParameterNamed:

    - setImage:forParameterNamed:

    And the generated interface for these methods shown as...

    // Set an image associated with a parameter on the receiver. This image will be used in display of the receiver throughout the system.
    @available(iOS 12.0, *)
    open func __setImage(_ image: INImage?, forParameterNamed parameterName: String)
    
    @available(iOS 12.0, *)
    open func __image(forParameterNamed parameterName: String) -> INImage?
    

    The docs or code suggestion of Xcode will not show you these, but you can use them in Swift 5 code:

        intent.__setImage(image, forParameterNamed: "spotName")
    

    Though, using underscore-leaded methods may be taken as using private APIs when submitting your app to App Store.

    This sort of things sometimes happens when Apple is swiftifying some methods and not completed yet.

    As for now, what you can do are...

    or