How to invoke a class method using performSelector() on AnyClass in Swift?

北慕城南 提交于 2020-07-06 10:41:26

问题


In ObjC you could simply invoke a class method using the class method from NSObject.

[Machine performSelector:@selector(calculate:) withObject:num];

But how do you do this in Swift 2.2?

@objc(Machine) // put it here, so you can simply copy/paste into Playground
class Machine: NSObject {
    static func calculate(param: NSNumber) -> String {
        if param.integerValue > 5 {
            return "42"
        }
        return "42" // there is only 1 answer to all the questions :D
    }
}

if let aClass = NSClassFromString("Machine") {
    let sel = #selector(Machine.calculate(_:))
    let num = NSNumber(integer: 1337)
    let answer = aClass.performSelector(sel, withObject: num) // compiler error
    // let answer = aClass.calculate(num)                     // <-- this works
    print(answer)
}

With this code I'm getting the following compiler error:

error: cannot invoke 'performSelector' with an argument list of type '(Selector, withObject: NSNumber)'

What am I missing here?


回答1:


AnyClass does not conform to NSObjectProtocol out of the box. I had to cast aClass as NSObjectProtocol to use performSelector (performSelector:withObject: is bridged to Swift as a method on NSObjectProtocol):

Swift 3:

if let aClass = NSClassFromString("Machine") {
    let sel = #selector(Machine.calculate(param:))
    let num = NSNumber(value: 1337)

    if let myClass = aClass as? NSObjectProtocol {
        if myClass.responds(to: sel) {
            let answer = myClass.perform(sel, with: num).takeRetainedValue() // this returns AnyObject, you may want to downcast to your desired type
            print(answer) // "42\n"
        }
    }
}

Swift 2.x:

(aClass as! NSObjectProtocol).performSelector(sel, withObject: num) // Unmanaged<AnyObject>(_value: 42) 

A little bit safer:

if let aClass = NSClassFromString("Machine") {
    let sel = #selector(Machine.calculate(_:))
    let num = NSNumber(integer: 1337)

    if let myClass = aClass as? NSObjectProtocol {
        if myClass.respondsToSelector(sel) {
            let answer = myClass.performSelector(sel, withObject: num).takeUnretainedValue()
            print(answer) // "42\n"
        }
    }
}

performSelector returns an Unmanaged object, that's why takeUnretainedValue() (or optionally takeRetainedValue() if you want to transfer memory ownership) are required.




回答2:


If you want to perform calculate on machine, just do:

Machine.calculate(NSNumber(integer: 1337))

If you need to call perform selector, then do:

if let aClass = NSClassFromString("Machine") as? AnyObject
{
    let sel = #selector(Machine.calculate(_:))
    let num = NSNumber(integer: 1337)
    let answer = aClass.performSelector(sel, withObject: num)
    print(answer)
}


来源:https://stackoverflow.com/questions/36208155/how-to-invoke-a-class-method-using-performselector-on-anyclass-in-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!