takeRetainedValue () или takeUnretainedValue () в Swift с библиотекой C ++ - PullRequest
0 голосов
/ 04 июля 2018

Я работаю над проектом Swift, в котором используется библиотека C, обернутая в C ++.

  • Библиотека предлагает вам возможность получать / устанавливать переменные синхронно и асинхронно.

  • Библиотека как методы обратного вызова, которая уведомляет, когда и даже произошло.

У меня есть эта функция в swift:

/*** 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);

Тогда в swift я использую следующий код:

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

Итак, мои вопросы будут:

  • Когда мне нужно использовать takeRetainedValue () или takeUnretainedValue () в соответствии с информацией, которую я могу получить из библиотеки C ++?

Спасибо.

1 Ответ

0 голосов
/ 06 июля 2018

Вам нужно передать оставленное значение, если вы хотите, чтобы ваш ClassCallback существовал, даже если все ваши ссылки Swift на него исчезнут, это создает утечку памяти без добавления правильной логики очистки. Если вы передаете необработанное Значение тогда, если все ваши быстрые ссылки исчезли, когда вы попытаетесь вернуть свой ClassCallback, вы потерпите крах.

В вашем обратном вызове вы можете взять необработанную ссылку, чтобы получить объект, предполагая, что вы хотите, чтобы он продолжал существовать с его текущим счетчиком ссылок в конце области действия. Если вы возьмете сохраненную ссылку, счетчик ссылок уменьшится и уничтожит объект, если это была последняя ссылка.

Что я обычно делаю, это передаю оставшуюся ссылку и беру необработанную ссылку, пока я не буду готов избавиться от объекта обратного вызова. Когда это происходит, я беру оставшееся значение указателя контекста (aPtr в вашем случае), чтобы сбалансировать оставшийся проход и заменить его новым соответствующим значением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...