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?

+3


source to share


1 answer


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

      

+4


source







All Articles