在ObjC中,您可以使用NSObject中的类方法简单地调用类方法.
[Machine performSelector:@selector(calculate:) withObject:num];
但是你如何在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) }
error: cannot invoke ‘performSelector’ with an argument list of type ‘(Selector,withObject: NSNumber)’
我在这里错过了什么?
解决方法
AnyClass不符合开箱即用的NSObjectProtocol.我必须将aClass转换为NSObjectProtocol以使用performSelector(performSelector:withObject:作为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)
更安全一点:
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返回一个Unmanaged对象,这就是为什么需要takeUnretainedValue()(或者如果你想传输内存所有权,可选择takeRetainedValue()).