Swift Protocol Compliance from an Objective-C Protocol Instance
I am looking for a way to dynamically map an Objective-C instance Protocol
to the appropriate Swift protocol.
I have a protocol defined in swift that is Objective-C compatible:
@objc(YHMyProtocol) protocol MyProtocol { }
I am trying to match in a function:
public func existMatch(_ meta: Protocol) -> Bool {
// Not working
if meta is MyProtocol {
return true
}
// Not working also
if meta is MyProtocol.Protocol {
return true
}
return false
}
This function is meant to be called from an Objective-C file:
if([Matcher existMatch:@protocol(YHMyProtocol)]) {
/* Do Something */
}
The function existMatch
always returns false.
I cannot figure out how to solve this. Am I missing something in the implementation?
source to share
Protocol
- opaque object type. It is defined in the generated header as:
// All methods of class Protocol are unavailable.
// Use the functions in objc/runtime.h instead.
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)
@interface Protocol : NSObject
@end
It doesn't match MyProtocol
, so is MyProtocol
it can't work. And while Swift can implicitly bind protocol metateps @objc
to Protocol
, it seems like it cannot do the opposite; so is MyProtocol.Protocol
doesn't work (but even if it did, it wouldn't work for derived protocols, since P.Protocol
types can only hold value P.self
).
If you want to check what meta
is a protocol type equivalent to or derived from MyProtocol
, you can use the Obj-C runtime function protocol_conformsToProtocol
:
@objc(YHMyProtocol) protocol MyProtocol { }
@objc protocol DerviedMyProtocol : MyProtocol {}
@objc class Matcher : NSObject {
@objc public class func existMatch(_ meta: Protocol) -> Bool {
return protocol_conformsToProtocol(meta, MyProtocol.self)
}
}
// the following Swift protocol types get implicitly bridged to Protocol instances
// when calling from Obj-C, @protocol gives you an equivalent Protocol instance.
print(Matcher.existMatch(MyProtocol.self)) // true
print(Matcher.existMatch(DerviedMyProtocol.self)) // true
If you just want to check which is meta
equivalent MyProtocol
, you can use protocol_isEqual
:
@objc class Matcher : NSObject {
@objc public class func existMatch(_ meta: Protocol) -> Bool {
return protocol_isEqual(meta, MyProtocol.self)
}
}
print(Matcher.existMatch(MyProtocol.self)) // true
print(Matcher.existMatch(DerviedMyProtocol.self)) // false
source to share