7

Using the Objective-C runtime, I can get a list of all of the @objc protocols an object conforms to:

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])]))
}

or all of the Objective-C protocols loaded by the runtime:

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])]))
}

But neither of these list any Swift protocols:

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 is 0 when I would expect it to return sizeof(Protocol) * 2 (since MyClass conforms to Equatable and Hashable).

Is there an interface exposed by the runtime to get a list of protocols an object conforms to?

JAL
  • 41,701
  • 23
  • 172
  • 300

1 Answers1

4

You can't. Swift protocols that are not ObjC ones only exist at compile time and do not really exist on the object itself (which is why their methods are dispatched statically based on the type of the variable).

Joseph Lord
  • 6,446
  • 1
  • 28
  • 32
  • Sorry for my rudeness, but this answer is word salad. The compiler knows. – original_username Nov 08 '17 at 00:02
  • 2
    The point is that while the compiler knows the runtime doesn't, the information is not captured in the compiled binary so you couldn't interrogate the particular object for information. I haven't been following recent developments around reflection so some of this may have have changed in last 18 months. – Joseph Lord Nov 08 '17 at 10:33
  • Cheers. Your comment would make a good answer :) I misinterpreted your original answer as "swift doesn't keep a db of protocol conformance" which wouldn't make sense in light of Swift's compile-time checks. – original_username Nov 09 '17 at 01:52
  • Can't be right, because you need type checking during runtime. When you `if let x as Protocol`, the runtime checks conformance. Just because the ObjC runtime doesn't see the Swift protocol, doesn't mean the metadata doesn't exist. You just need different API from the Swift runtime. – Léo Natan Jul 18 '20 at 17:07
  • You might be right at least for `as?` and `as!` casts )a pure `as` cast is checked at compile time and will be optimised out or into bridging. For `as?` and `as!` it probably needs to know in some way although it is likely the mangled type names not the protocol names as you know them. I'm just guessing now though. We could check the source code (not possible in 2016 when I answered I think). – Joseph Lord Jul 19 '20 at 11:08
  • Thinking more @LeoNatan what is the x in your example? If it is the concrete type it will tell you it should be an `as` cast won't it which would be compile time checked so this is about the case where x is a different protocol type that may or may not conform to Protoco that is being downcastl. Now as a protocol type being passed around there may well be additional type information with it, a reference to the type itself which could be checked for conformances that you may not get with a Swift class or at least a struct. – Joseph Lord Jul 30 '20 at 15:59