次のコードを呼び出すときに、Swift で C 関数に「self」を渡そうとしています。
var callbackStruct : AURenderCallbackStruct =
AURenderCallbackStruct.init(
inputProc: recordingCallback,
inputProcRefCon: UnsafeMutablePointer<Void>
)
ここで「self」を UnsafeMutablePointer 型にキャストする理想的な方法は何ですか?
ベストアンサー1
オブジェクトポインタ(つまり、参照タイプUnsafePointer<Void>
)は(Swift 3の のSwiftマッピング)に変換できconst void *
、UnsafeRawPointer
その逆も可能です。Objective-Cでは次のように記述します。
void *voidPtr = (__bridge void*)self;
//
MyType *mySelf = (__bridge MyType *)voidPtr;
(見る3.2.4 ブリッジキャストこれらのキャストの正確な意味については、Clang ARC ドキュメントを参照してください。
Swift には、この目的のための 型があります。ではなくUnmanaged
を使用するため、使用が少し面倒です。次に、2 つのヘルパー メソッドを示します (Objective-Cキャストにちなんで名付けられています)。COpaquePointer
UnsafePointer<Void>
__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) // ***
}
「複雑な」式は、Swift の厳密な型システムを満たすためにのみ必要です。コンパイルされたコードでは、これは単にポインタ間のキャストです。( ***
「安全でない」メソッドを使用する場合は、コメントに示されているように短く記述できますが、コンパイルされたコードは同一です。)
このヘルパーメソッドを使用すると、self
C関数に渡すことができます。
let voidPtr = bridge(self)
(またはUnsafeMutablePointer<Void>(bridge(self))
C関数が可変ポインタを必要とする場合)、それをオブジェクトポインタに変換します(たとえばコールバック関数で)。
let mySelf : MyType = bridge(voidPtr)
所有権の移転は行われないため、self
void ポインターが使用されている限り、それが存在することを確認する必要があります。
完全を期すために、Objective-CのSwift版__bridge_retained
と同等のもの__bridge_transfer
は次のようになります。
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 ポインターにキャストし、オブジェクトを保持します。voidbridgeTransfer()
ポインターをオブジェクト ポインターに戻し、保持を消費します。
利点は、強い参照が保持されるため、呼び出し間でオブジェクトの割り当てを解除できないことです。欠点は、呼び出しを適切にバランスさせる必要があり、保持サイクルが簡単に発生する可能性があることです。
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()
}
「安全でないポインタ」に関連する変更については、以下で説明されています。