Ответ 1
Указатель объекта (т.е. экземпляр ссылочного типа) может быть
преобразуется в UnsafePointer<Void>
(Swift-отображение const void *
, UnsafeRawPointer
в Swift 3) и обратно. В Objective-C вы должны написать
void *voidPtr = (__bridge void*)self;
//
MyType *mySelf = (__bridge MyType *)voidPtr;
(См. 3.2.4 Bridged casts в документации Clang ARC для точного значения этих слепки.)
Для этой цели Swift имеет тип Unmanaged
.
Это немного громоздко, потому что он работает с COpaquePointer
вместо UnsafePointer<Void>
. Вот два вспомогательных метода
(названный в честь Objective-C __bridge
):
func bridge<T : AnyObject>(obj : T) -> UnsafePointer<Void> {
return UnsafePointer(Unmanaged.passUnretained(obj).toOpaque())
// return unsafeAddressOf(obj) // ***
}
func bridge<T : AnyObject>(ptr : UnsafePointer<Void>) -> T {
return Unmanaged<T>.fromOpaque(COpaquePointer(ptr)).takeUnretainedValue()
// return unsafeBitCast(ptr, T.self) // ***
}
"Сложное" выражение необходимо только для того, чтобы удовлетворить Swifts
строгая система. В скомпилированном коде это просто литье
между указателями. (Его можно записать короче, как указано в комментариях ***
если вы готовы использовать "небезопасные" методы, но скомпилированные
код идентичен.)
Используя эти вспомогательные методы, вы можете передать self
функции C как
let voidPtr = bridge(self)
(или UnsafeMutablePointer<Void>(bridge(self))
, если требуется функция C
изменяемый указатель) и преобразовать его обратно в указатель объекта - например,
в функции обратного вызова - как
let mySelf : MyType = bridge(voidPtr)
Передача права собственности не происходит, поэтому вы должны убедиться, что self
существует, пока используется указатель void.
И для полноты, эквивалент Swift __bridge_retained
и __bridge_transfer
из Objective-C будет
func bridgeRetained<T : AnyObject>(obj : T) -> UnsafePointer<Void> {
return UnsafePointer(Unmanaged.passRetained(obj).toOpaque())
}
func bridgeTransfer<T : AnyObject>(ptr : UnsafePointer<Void>) -> T {
return Unmanaged<T>.fromOpaque(COpaquePointer(ptr)).takeRetainedValue()
}
bridgeRetained()
выводит указатель на указатель на void и
сохраняет объект. bridgeTransfer()
преобразует
указатель void обратно к указателю объекта и потребляет сохранение.
Преимущество заключается в том, что объект не может быть освобожден между потому что существует сильная ссылка. Недостатком является то, что вызовы должны быть должным образом сбалансированы и что это может легко вызвать сохранение циклов.
Обновление для Swift 3 (Xcode 8):
func bridge<T : AnyObject>(obj : T) -> UnsafeRawPointer {
return UnsafeRawPointer(Unmanaged.passUnretained(obj).toOpaque())
}
func bridge<T : AnyObject>(ptr : UnsafeRawPointer) -> T {
return Unmanaged<T>.fromOpaque(ptr).takeUnretainedValue()
}
func bridgeRetained<T : AnyObject>(obj : T) -> UnsafeRawPointer {
return UnsafeRawPointer(Unmanaged.passRetained(obj).toOpaque())
}
func bridgeTransfer<T : AnyObject>(ptr : UnsafeRawPointer) -> T {
return Unmanaged<T>.fromOpaque(ptr).takeRetainedValue()
}
Соответствующие изменения в "небезопасных указателях" описаны в