使用C ++库在Swift中使用takeRetainedValue()或takeUnretainedValue()

时间:2018-07-04 10:44:29

标签: c++ c swift

我正在开发一个Swift项目,该项目使用包装在C ++中的C库。

  • 该库为您提供了同步和异步获取/设置变量的可能性。

  • 作为回调方法的库,用于通知何时甚至发生。

我很快拥有此功能:

/*** Convert const void* To Any T ***/

func bridgeToTypeRetained<T : AnyObject>(ptr : UnsafeMutableRawPointer) -> T {
   return Unmanaged<T>.fromOpaque(ptr).takeRetainedValue()
}

func bridgeToTypeUnretained<T : AnyObject>(ptr : UnsafeRawPointer) -> T {
   return Unmanaged<T>.fromOpaque(ptr).takeUnretainedValue()
}

/*** Convert const void* To Any T ***/
func bridgeToPointerRetained<T : AnyObject>(obj : T) -> UnsafeMutableRawPointer {
    return UnsafeMutableRawPointer(Unmanaged.passRetained(obj).toOpaque())
}

func bridgeToPointerUnretained<T : AnyObject>(obj : T) -> UnsafeMutableRawPointer {
    return UnsafeMutableRawPointer(Unmanaged.passUnretained(obj).toOpaque())
}

对于从库中实现回调,在库中,我具有以下定义:

DllExport void STDCALL CpProxyAvOpenhomeOrgInfo1SetPropertyTrackCountChanged(THandle aHandle, OhNetCallback aCallback, void* aPtr);

typedef void (STDCALL *OhNetCallback)(void* aPtr);

然后我迅速使用以下代码:

 CpProxyAvOpenhomeOrgInfo1SetPropertyTrackCountChanged(myHandle, { (pointer) in

 if pointer != nil{
    let myClass:MyClass = bridgeToTypeRetained(ptr: pointer!)
    myClass.aValu = 0 //CRASH BAD ACCESS
    let myClass:MyClass = bridgeToTypeUnretained(ptr: pointer!)
    myClass.aValu = 0 //NO CRASH
 }

 }, bridgeToPointerRetained(obj: self))

对于实现异步操作,在库中有以下定义:

DllExport void STDCALL CpProxyAvOpenhomeOrgInfo1BeginCounters(THandle aHandle, OhNetCallbackAsync aCallback, void* aPtr);

typedef void (STDCALL *OhNetCallbackAsync)(void* aPtr, OhNetHandleAsync aAsync);

然后迅速使用以下代码

    let classCallback = ClassCallback()
    classCallback.classObject = self

    CpProxyAvOpenhomeOrgInfo1BeginCounters(prxHandleId, { (pointer, ohNetAsync) in

        if pointer != nil && ohNetAsync != nil{

            let classCallback : ClassCallback = bridgeToTypeRetained(ptr: pointer!)
            classCallback.classObject.aValue = 1 //NO CRASH

        }


    }, bridgeToPointerRetained(obj: classCallback))

所以我的问题是:

  • 何时我必须根据我可以从C ++库获得的信息使用takeRetainedValue()或takeUnretainedValue()?

谢谢。

1 个答案:

答案 0 :(得分:1)

如果您希望ClassCallback存在,即使您所有对它的Swift引用都消失了,也需要传递一个保留值,这会导致内存泄漏而没有添加适当的清除逻辑。一个未保留的值,那么当您尝试取回ClassCallback时,如果所有快速引用都消失了,则会崩溃。

在您的回调中,您可以采用一个未保留的引用来获取该对象,前提是您希望该对象以作用域结尾处的当前引用计数继续存在。如果您使用保留的引用,则引用计数将减少并破坏该对象(如果这是最后一个引用)。

我通常要做的是传递保留的引用,并获取未保留的引用,直到准备好处理回调对象为止。发生这种情况时,我将使用上下文指针的保留值(在您的情况下为aPtr)来平衡保留的传递并将其替换为新的适当值。