self を UnsafeMutablePointer にキャストする方法 Swiftで入力する 質問する

self を UnsafeMutablePointer にキャストする方法 Swiftで入力する 質問する

次のコードを呼び出すときに、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キャストにちなんで名付けられています)。COpaquePointerUnsafePointer<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 の厳密な型システムを満たすためにのみ必要です。コンパイルされたコードでは、これは単にポインタ間のキャストです。( ***「安全でない」メソッドを使用する場合は、コメントに示されているように短く記述できますが、コンパイルされたコードは同一です。)

このヘルパーメソッドを使用すると、selfC関数に渡すことができます。

 let voidPtr = bridge(self)

(またはUnsafeMutablePointer<Void>(bridge(self))C関数が可変ポインタを必要とする場合)、それをオブジェクトポインタに変換します(たとえばコールバック関数で)。

 let mySelf : MyType = bridge(voidPtr)

所有権の移転は行われないため、selfvoid ポインターが使用されている限り、それが存在することを確認する必要があります。


完全を期すために、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()
}

「安全でないポインタ」に関連する変更については、以下で説明されています。

おすすめ記事