使用 Objective-C 运行时,我可以获取一个对象符合的所有 @objc
协议列表:
let obj = NSObject()
var pc: UInt32 = 0
let plist = class_copyProtocolList(object_getClass(obj), &pc)
print("\(obj.dynamicType) conforms to \(pc) protocols")
for i in 0 ..< Int(pc) {
print(String(format: "Protocol #%d: %s", arguments: [i, protocol_getName(plist[i])]))
}
或者运行时加载的所有Objective-C协议:
var allProtocolCount: UInt32 = 0
let protocols = objc_copyProtocolList(&allProtocolCount)
print("\(allProtocolCount) total protocols")
for i in 0 ..< Int(allProtocolCount) {
print(String(format: "Protocol #%d: %s", arguments: [i, protocol_getName(protocols[i])]))
}
但是这两个都没有列出任何 Swift 协议:
func == (lhs: MyClass, rhs: MyClass) -> Bool {
return lhs.value == rhs.value
}
class MyClass: Equatable, Hashable {
var value: Int
var hashValue: Int {
return value
}
init(value: Int) {
self.value = value
}
}
var count: UInt32 = 0;
let strProtocols = class_copyProtocolList(MyClass.self, &count) // 0x0000000000000000
strProtocols
的值为0,但我期望它应该返回sizeof(Protocol) * 2
(因为MyClass
遵循了Equatable
和Hashable
协议)。
运行时是否提供了一个接口来获取对象所遵循的协议列表?
if let x as Protocol
时,运行时会检查一致性。仅仅因为 ObjC 运行时看不到 Swift 协议,这并不意味着元数据不存在。你只需要使用来自 Swift 运行时的不同 API。 - Léo Natanas?
和as!
强制转换,你可能是正确的(纯as
转换在编译时进行检查并将被优化或映射到桥接)。对于as?
和as!
,它可能需要以某种方式知道,尽管很可能是类型名称而不是您所知道的协议名称。我现在只是猜测。我们可以检查源代码(我认为在2016年回答时不可能)。 - Joseph Lord