从Objective-C协议实例匹配Swift协议

时间:2017-07-10 11:58:05

标签: objective-c swift bridging

我正在寻找一种方法来动态匹配Objective-C Protocol实例和相应的Swift协议。

我在swift中定义了一个与Objective-C兼容的协议:

@objc(YHMyProtocol) protocol MyProtocol { }

我尝试在函数中执行匹配:

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
}

此函数旨在从Objective-C文件中调用:

if([Matcher existMatch:@protocol(YHMyProtocol)]) {
    /* Do Something */
}

existMatch函数始终返回false。

我无法弄清楚如何解决这个问题。我在实施中遗漏了什么吗?

1 个答案:

答案 0 :(得分:4)

Protocol是一种不透明的对象类型。它在生成的标题中定义为:

// 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

它不符合MyProtocol,因此is MyProtocol无效。而且,尽管Swift可以隐式地将@objc协议元类型桥接到Protocol,但它看起来不能反过来;这就是为什么is MyProtocol.Protocol不起作用的原因(但即使它确实如此,它也不适用于派生的协议;因为P.Protocol类型目前只能保留值P.self)。

如果要检查meta是与MyProtocol等效或派生的协议类型,可以使用Obj-C运行时函数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

如果只是想要检查meta是否等同于MyProtocol,您可以使用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