次のコードを呼び出すときに、SwiftのC関数に「self」を渡そうとします。
var callbackStruct : AURenderCallbackStruct =
AURenderCallbackStruct.init(
inputProc: recordingCallback,
inputProcRefCon: UnsafeMutablePointer<Void>
)
ここで「自己」をUnsafeMutablePointer型にキャストする理想的な方法は何ですか?
オブジェクトポインター(つまり、参照型のインスタンス)は、Swift内のUnsafePointer<Void>
(const void *
、UnsafeRawPointer
のSwiftマッピングに変換できます。 _ 3)および戻る。 Objective-Cでは、次のように記述します
void *voidPtr = (__bridge void*)self;
//
MyType *mySelf = (__bridge MyType *)voidPtr;
(これらのキャストの正確な意味については、Clang ARCドキュメントの .2.4 Bridged casts を参照してください。)
Swiftには、そのためのUnmanaged
タイプがあります。 UnsafePointer<Void>
ではなくCOpaquePointer
で動作するため、使用するのは少し面倒です。次に、2つのヘルパーメソッド(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) // ***
}
「複雑な」式は、Swiftの厳密な型システムを満たすためにのみ必要です。コンパイルされたコードでは、これは単なるポインター間のキャストです。 (「安全でない」メソッドを使用する場合は***
コメントに示されているように短く書くことができますが、コンパイルされたコードは同じです。)
このヘルパーメソッドを使用すると、self
をC関数に次のように渡すことができます。
let voidPtr = bridge(self)
(または、C関数が可変ポインターを必要とする場合はUnsafeMutablePointer<Void>(bridge(self))
)、それをオブジェクトポインターに変換します。コールバック関数で– as
let mySelf : MyType = bridge(voidPtr)
所有権の譲渡は行われないため、voidポインターが使用されている限り、self
が存在することを確認する必要があります。
完全を期すために、Objective-Cの__bridge_retained
および__bridge_transfer
と同等のSwiftは
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ポインターをオブジェクトポインターに変換し、retainを消費します。
利点は、強い参照が保持されるため、呼び出し間でオブジェクトの割り当てを解除できないことです。欠点は、呼び出しのバランスを適切にとる必要があり、保持サイクルが発生しやすいことです。
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()
}
「安全でないポインター」に関連する変更については、
これはwithUnsafeMutablePointer
の目的であるように思えます-任意のSwiftポインターをCポインターに変換します。しかし、私がテストしたコードは安全に動作します):
var mself = self
withUnsafeMutablePointer(&mself) { v in
let v2 = UnsafeMutablePointer<Void>(v)
myStruct.inputProcRefCon = v2
}
func bridge<T : AnyObject>(obj : T) -> UnsafePointer<Void> {
return UnsafePointer(Unmanaged.passUnretained(obj).toOpaque())
}
func bridge<T : AnyObject>(ptr : UnsafePointer<Void>) -> T {
return Unmanaged<T>.fromOpaque(ptr).takeUnretainedValue()
}
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(ptr).takeRetainedValue()}
この答えは、 Martin Rの答え のように、コールバックのトピック固有ではありませんが、役に立つかもしれません...
通常、&
演算子を使用して、安全でないvoidポインターに任意の型の値を渡すことができます。
func baz(p: UnsafeMutablePointer<Void>) -> String {
return "\(p)"
}
var num = 5
print(baz(&num))
ただし、self
を渡すには、self
が変更可能なコンテキストで渡す必要があります。つまり、参照型ではなく、値型の変更メソッド(またはinit
)でこれを行う必要があります。
struct FooValue {
mutating func bar() {
print(baz(&self))
}
}
var myFooValue = FooValue()
myFooValue.bar()
参照型を使用する場合は、参照のローカルコピーを作成し、それにポインタを渡す必要があります。
class FooReference {
func bar() {
var localSelf = self
print(baz(&localSelf))
}
}
let myFooReference = FooReference()
myFooReference.bar()