djinni - указатели и циклические ссылки между C++ и swift/ target C/java

У меня есть два интерфейса Джинни, один из которых будет реализован в Swift/ Objective C/ Java SwiftObj и один будет реализован в C++ CPPObj,

SwiftObj = interface +o +j {
    someSwiftMethod();
}

CPPObj = interface +c {
    static create(swiftObj: SwiftObj): CPPObj;
    someCPPMethod();
}

Они оба имеют указатель друг на друга, поэтому SwiftObj сможет позвонить someCPPMethod() из CPPObj и наоборот: CPPObj сможет позвонить someSwiftMethod() от SwiftObj:

В скором времени:

  • переменная класса: var myCPPObj: SwiftObj!
  • создание: myCPPObj = MyCPPObj.create(self)
  • Использование: myCPPObj.someCPPMethod()

В с ++:

  • переменная класса: shared_ptr<SwiftObj> mySwiftObj_;
  • Использование: mySwiftObj_->someSwiftMethod();

Таким образом, вопрос здесь заключается в том, что эти объекты не собирают мусор из-за циклической ссылки (я попытался удалить циклическую ссылку, и они получили GCed).

Но затем я попытался установить один из этих указателей как слабый. В C++: weak_ptr<SwiftObj> mySwiftObj_;... но это сделало mySwiftObj_ Быть GCed мгновенно, даже когда он на самом деле все еще существует в быстрой. То же самое произошло, когда я установил слабый указатель swift и сильный C++.

Так как я могу справиться с этой ситуацией? (кроме ручной установки одного из этих указателей как ноль). Есть идеи о том, как на самом деле работают указатели в джиннах?

Спасибо!

1 ответ

Решение

К сожалению, нет какой-либо слабой ссылки / указателя, которая может понимать владение разными языками, и Джинни не пытается добавить его. Доступная слабая семантика в C++ и Swift знает только о ссылках в одном и том же языке, поэтому вы видите мгновенное поведение GC. Это сгенерированный Джинни прокси-объект, который слабо удерживается и становится неиспользованным, но как только прокси исчезает, он освобождает реальный объект.

Я думаю, что самым простым подходом было бы разделить объект Swift на два объекта, назовем их Owner и Listener. В вашем примере только Listener должен быть объектом Djinni и реализовывать someSwiftMethod(), Возможно, у вас есть и другие причины, по которым владелец должен быть интерфейсом Джинни. Настройте свой график владения следующим образом. Простите за искусство ASCII: Свифт слева, С ++ справа.

                  <- Swift|C++ ->

  SwiftOwner ------------------------> CppObj
    ^    |                               |
    |    |                               |
 (weak)  |                               |
    |    v                               |
  SwiftListener <------------------------+

В этом сценарии круговые и слабые реферы ограничены Swift, поэтому будут работать так, как вы ожидаете, и SwiftListener может пересылать по методам SwiftOwner как необходимо. Эта модель оптимизирована для случая, когда внешнее использование этих объектов исходит от Swift. Такие пользователи должны иметь ссылку на SwiftOwner, Если ваше основное использование в C++, вы можете изменить картину, или вы можете иметь внешние объекты C++, содержащие сильную ссылку на SwiftOwner. В любом случае, SwiftOwner не имеет (сильных) циклических ссылок на него, и как только он будет выпущен, будут выпущены и другие два объекта.

Другие вопросы по тегам