Допустим, у нас есть следующий API Objective-C:
- (id)foo:(Protocol *)proto;
Что импортируется в Swift как:
func foo(_ proto: Protocol) -> Any
Да, это одна из тех вещей, которая дает нам прокси-объект. Их, как правило, раздражает использование в Swift, поэтому предположим, что мы хотим сделать обертку вокруг этой вещи, чтобы сделать ее немного более дружелюбной. Сначала мы определим пару Objective-C-совместимых протоколов:
@objc protocol Super {}
@objc protocol Sub: Super {}
Теперь мы определяем функцию, которая принимает протокол, соответствующий Super
, и передает его foo()
, а затем мы вызываем его с Sub
в качестве параметра, чтобы посмотреть, работает ли он:
func bar<P: Super>(proto: P.Type) {
let proxy = foo(proto)
// do whatever with the proxy
}
bar(proto: Sub.self)
Ну, это не компилируется. Сообщение об ошибке:
error: cannot convert value of type 'P.Type' to expected argument type 'Protocol'
Вот некоторые вещи, которые компилирует (в основном):
func bar<P: Super>(proto: P.Type) {
// when called with 'Sub.self' as 'proto':
print(type(of: proto)) // Sub.Protocol
print(type(of: Sub.self)) // Sub.Protocol
print(proto == Sub.self) // true
let proxy1 = foo(Sub.self) // compiles, runs, works
let proxy2 = foo(proto) // error: cannot convert value of type 'P.Type' to expected argument type 'Protocol'
}
Хорошо, это почти то же самое, что и Sub.self
, за исключением того, что я не могу передать его чему-то, требующему протокол Objective-C. Хм.
Проблема в том, что, хотя тот факт, что Sub
соответствует Super
, означает, что это должен быть протокол Objective C, компилятор этого не понимает. Можем ли мы обойти это и соединить его вручную? Что ж, давайте посмотрим на интерфейс Protocol
, чтобы увидеть, есть ли что-нибудь, что мы можем ...
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0)
@interface Protocol : NSObject
@end
О. Хмм.
Ну, тот факт, что Protocol
является полноценным подклассом NSObject
, говорит о том, что это, вероятно, работа моего самого лучшего фаворита - магического моста Swift <-> Objective-C, который выполняет нетривиальные преобразования на вещи без того, чтобы быть очевидным, что происходит. Ну, это дает мне идею, по крайней мере; Я должен быть в состоянии вручную вызвать мост, приведя к AnyObject
и, надеюсь, получить объект Protocol
таким образом, возможно, as!
используя его или что-то еще. Это работает?
print(Sub.self as AnyObject) // <Protocol: 0x012345678>
Ну, это многообещающе. И когда я попробую это на моем общем параметре?
print(proto as AnyObject) // Terminated due to signal: SEGMENTATION FAULT (11)
О, давай .
Я подозреваю, что это, вероятно, ошибка в компиляторе, и я планирую протестировать несколько вещей, чтобы определить, так ли это, но, поскольку исходники Swift требуют геологического возраста для компиляции, я решил опубликовать это здесь, пока Я жду. У кого-нибудь есть понимание и / или обходные пути в отношении того, что здесь происходит?