Соответствие протоколу Swift из экземпляра протокола Objective C

Я ищу способ динамически сопоставить 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 ответ

Решение

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 не может работать И, хотя Свифт может неявно мост @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
Другие вопросы по тегам