djinni - C++ 和 swift/objective C/java 之间的指针和循环引用

djinni - pointers and circular references between C++ and swift/objective C/java

我有两个 djinni 接口,一个用 Swift/objective C/java SwiftObj 实现,一个用 C++ CPPObj 实现。

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

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

它们都有一个指向彼此的指针,因此 SwiftObj 将能够调用 CPPObjsomeCPPMethod(),反之亦然:CPPObj 将能够调用从 SwiftObj:

调用 someSwiftMethod()

在swift中:

在 C++ 中:

所以这里的问题是,由于循环引用,这些对象没有得到垃圾回收(我尝试并删除了循环引用,它们得到了 GC)。

但后来我尝试将其中一个指针设置为弱指针。在 C++ 中:weak_ptr<SwiftObj> mySwiftObj_; ... 但这使得 mySwiftObj_ 立即被 GC,即使它实际上仍然存在于 swift 中。当我将 swift 指针设置为 weak 并将 C++ 设置为 strong 时,同样的事情发生了。

那么我该如何处理这种情况呢? (除了手动将这些指针之一设置为空)。关于指针在 djinni 中实际如何工作的任何见解?

谢谢!

不幸的是,没有一种可以理解跨语言所有权的弱 reference/pointer,Djinni 也没有尝试添加一个。 C++ 和 Swift 中可用的弱语义只知道同一语言中的引用,这就是为什么您会看到即时 GC 行为。它是Djinni生成的代理对象,被弱持有,变得不被使用,但是一旦代理消失,它就会释放真正的对象。

我认为最简单的方法是将 Swift 对象拆分为两个对象,我们称它们为 Owner 和 Listener。在您的示例中,只有 Listener 需要是 Djinni 对象,并实现 someSwiftMethod()。也许您还有其他原因让 Owner 成为 Djinni 界面。如下设置您的所有权图。请原谅 ASCII 艺术:Swift 在左边,C++ 在右边。

                  <- Swift|C++ ->

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

在这种情况下,循环和弱引用都被限制在 Swift,所以会按你预期的那样工作,并且 SwiftListener 可以根据需要将方法转发到 SwiftOwner .该模型针对这些对象的外部使用来自 Swift 的情况进行了优化。这样的用户应该持有对 SwiftOwner 的引用。如果您的主要用途是在 C++ 中,您可以反转图片,或者您可以让外部 C++ 对象持有对 SwiftOwner 的强引用。无论哪种方式,SwiftOwner 都没有对它的(强)循环引用,一旦它被释放,其他两个对象也会被释放。