ios - ¿Cómo invocar un método de clase usando performSelector() en AnyClass en Swift?
reflection swift2.2 (2)
Si desea realizar el cálculo en la máquina, solo haga lo siguiente:
Machine.calculate(NSNumber(integer: 1337))
Si necesita llamar al selector de ejecución, haga lo siguiente:
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)
}
En ObjC, simplemente podría invocar un método de clase utilizando el método de clase de NSObject
.
[Machine performSelector:@selector(calculate:) withObject:num];
¿Pero cómo haces esto en 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)
}
Con este código recibo el siguiente error de compilación:
error: no se puede invocar ''performSelector'' con una lista de argumentos de tipo ''(Selector, withObject: NSNumber)''
¿Que me estoy perdiendo aqui?
AnyClass
no se ajusta a NSObjectProtocol
fuera de la caja. Tuve que lanzar aClass
como NSObjectProtocol
para usar performSelector
( performSelector:withObject:
está performSelector:withObject:
a Swift como un método en 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)
Un poco más seguro:
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
devuelve un objeto no Unmanaged
, por eso takeUnretainedValue()
(u opcionalmente takeRetainedValue()
si desea transferir la propiedad de la memoria) son necesarios.