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 не имеет (сильных) циклических ссылок на него, и как только он будет выпущен, будут выпущены и другие два объекта.