Как направить себя в UnsafeMutablePointer <Void> type в swift

Попытка передать "self" функции C в swift при вызове следующего кода:

var callbackStruct : AURenderCallbackStruct = 
    AURenderCallbackStruct.init(
      inputProc: recordingCallback,
      inputProcRefCon: UnsafeMutablePointer<Void>
    )

Каков идеальный способ включить "я" в тип UnsafeMutablePointer?

Ответ 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()
}

Соответствующие изменения в "небезопасных указателях" описаны в

Ответ 2

Мне кажется, что это то, что withUnsafeMutablePointer для - преобразовать произвольный указатель Swift в C-указатель. По-видимому, вы могли бы это сделать (я не пробовал, но проверенный мной код работает безопасно):

var mself = self 
withUnsafeMutablePointer(&mself) { v in
    let v2 = UnsafeMutablePointer<Void>(v)
    myStruct.inputProcRefCon = v2
}

Ответ 3

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()}

Ответ 4

Этот ответ не выглядит как конкретный для обратного вызова как ответ Martin R, но может быть полезен...

Обычно вы можете передать значение любого типа небезопасному указателю void с помощью оператора &:

func baz(p: UnsafeMutablePointer<Void>) -> String {
    return "\(p)"
}

var num = 5
print(baz(&num))

Однако, чтобы пройти self, вам нужно сделать это в контексте, где self является изменяемым. Это означает, что вам нужно будет сделать это в методе mutating (или 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()