Как составить список протоколов, которым соответствует объект?

Используя среду выполнения Objective-C, я могу получить список всех @objc протоколов, которым соответствует объект:

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

или все протоколы Objective-C, загруженные средой выполнения:

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

Но ни один из них не перечисляет какие-либо протоколы Swift:

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 равен 0, когда я ожидаю, что он вернет sizeof(Protocol) * 2 (поскольку MyClass соответствует Equatable и Hashable).

Существует ли интерфейс, предоставляемый средой выполнения для получения списка протоколов, которым соответствует объект?


person JAL    schedule 24.03.2016    source источник


Ответы (1)


Вы не можете. Протоколы Swift, которые не являются протоколами ObjC, существуют только во время компиляции и на самом деле не существуют в самом объекте (поэтому их методы отправляются статически в зависимости от типа переменной).

person Joseph Lord    schedule 26.03.2016
comment
Извините за грубость, но этот ответ - словесный салат. Компилятор знает. - person original_username; 08.11.2017
comment
Дело в том, что, хотя компилятор знает, что среда выполнения этого не знает, информация не сохраняется в скомпилированном двоичном файле, поэтому вы не можете запросить информацию у конкретного объекта. Я не следил за последними событиями, связанными с рефлексией, так что кое-что из этого могло измениться за последние 18 месяцев. - person Joseph Lord; 08.11.2017
comment
Ваше здоровье. Ваш комментарий был бы хорошим ответом :) Я неправильно истолковал ваш первоначальный ответ, поскольку Swift не поддерживает соответствие протоколу базы данных, что не имело бы смысла в свете проверок времени компиляции Swift. - person original_username; 09.11.2017
comment
Не может быть прав, потому что вам нужна проверка типов во время выполнения. Когда вы if let x as Protocol, среда выполнения проверяет соответствие. Тот факт, что среда выполнения ObjC не видит протокол Swift, не означает, что метаданных не существует. Вам просто нужен другой API из среды выполнения Swift. - person Leo Natan; 18.07.2020
comment
Возможно, вы правы, по крайней мере, для приведения as? и as! ) чистое приведение as проверяется во время компиляции и будет оптимизировано или преобразовано в мост. Для as? и as!, вероятно, нужно каким-то образом знать, хотя, вероятно, искаженные имена типов, а не имена протоколов, которые вы их знаете. Хотя я сейчас только предполагаю. Мы могли бы проверить исходный код (это было невозможно в 2016 году, когда я ответил, что думаю). - person Joseph Lord; 19.07.2020
comment
Думая больше @LeoNatan, что такое x в вашем примере? Если это конкретный тип, он сообщит вам, что это должно быть приведение as, не так ли, которое будет проверено во время компиляции, так что это касается случая, когда x - это другой тип протокола, который может или не может соответствовать Protoco, который в настоящее время поникший Теперь, когда передается тип протокола, вполне может быть дополнительная информация о типе, ссылка на сам тип, который можно проверить на соответствие, чего вы не можете получить с классом Swift или, по крайней мере, со структурой. - person Joseph Lord; 30.07.2020