如何在 Swift 中的 AnyClass 上使用 performSelector() 调用类方法?
Posted
技术标签:
【中文标题】如何在 Swift 中的 AnyClass 上使用 performSelector() 调用类方法?【英文标题】:How to invoke a class method using performSelector() on AnyClass in Swift? 【发布时间】:2016-03-24 19:07:18 【问题描述】:在 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)
使用此代码,我收到以下编译器错误:
错误:无法使用类型为“(Selector, withObject: NSNumber)”的参数列表调用“performSelector”
我在这里错过了什么?
【问题讨论】:
这绝对不是没有意义的,如果你想使用外部源的类怎么办?例如。从 plist 中的字符串中读取类名,是否要根据每个可能的对象编写 if 条件? 相关:Access Private UIKit Function Without Using Bridging Header 【参考方案1】: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()
)。
【讨论】:
这很有趣,因为将其转换为? AnyObject 为我工作 @Knight0fDragon Casting toAnyObject
会起作用,因为AnyClass
实际上是元类型AnyObject.Type
的类型别名。你可能会收到一个警告,因为它们是同一类型,所以抛弃成功。不过,将类强制转换为对象可能不是一个好主意。
@Knight0fDragon 你只能在 Objective-C 类型上使用 performSelector
,而不是纯 Swift 类型。尝试一下。这就是我检查NSObjectProtocol
一致性的原因。
"你只能在 Objective-C 类型上使用 performSelector,而不是纯 Swift 类型。"但实际上,在运行时,纯 Swift 类型 do 支持 .respondsToSelector()
、.performSelector()
等。因此转换为 AnyObject
(以克服在编译时缺乏对此类支持的了解)并使用他们确实工作,不需要类型符合NSObjectProtocol
。
奇怪的是,Swift 4 会发出警告,试图将 AnyClass
转换为 NSObjectProtocol
,这让我很恼火。在运行时它仍然有效,但试图保持警告项目的干净。有人有想法吗?【参考方案2】:
如果您想在机器上执行计算,只需:
Machine.calculate(NSNumber(integer: 1337))
如果你需要调用执行选择器,那么做:
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)
【讨论】:
以上是关于如何在 Swift 中的 AnyClass 上使用 performSelector() 调用类方法?的主要内容,如果未能解决你的问题,请参考以下文章
Swift 元类型selfSelfAnyObjectAny和AnyClass
Swift 元类型selfSelfAnyObjectAny和AnyClass
Swift基础-AnyObject&Any&AnyClass
Swift 2.1 中的 NSClassFromString