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
将能够调用 CPPObj
的 someCPPMethod()
,反之亦然:CPPObj
将能够调用从 SwiftObj
:
调用 someSwiftMethod()
在swift中:
- class变量:
var myCPPObj: SwiftObj!
- 创作:
myCPPObj = MyCPPObj.create(self)
- 用法:
myCPPObj.someCPPMethod()
在 C++ 中:
- class 变量:
shared_ptr<SwiftObj> mySwiftObj_;
- 用法:
mySwiftObj_->someSwiftMethod();
所以这里的问题是,由于循环引用,这些对象没有得到垃圾回收(我尝试并删除了循环引用,它们得到了 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 都没有对它的(强)循环引用,一旦它被释放,其他两个对象也会被释放。
我有两个 djinni 接口,一个用 Swift/objective C/java SwiftObj
实现,一个用 C++ CPPObj
实现。
SwiftObj = interface +o +j {
someSwiftMethod();
}
CPPObj = interface +c {
static create(swiftObj: SwiftObj): CPPObj;
someCPPMethod();
}
它们都有一个指向彼此的指针,因此 SwiftObj
将能够调用 CPPObj
的 someCPPMethod()
,反之亦然:CPPObj
将能够调用从 SwiftObj
:
someSwiftMethod()
在swift中:
- class变量:
var myCPPObj: SwiftObj!
- 创作:
myCPPObj = MyCPPObj.create(self)
- 用法:
myCPPObj.someCPPMethod()
在 C++ 中:
- class 变量:
shared_ptr<SwiftObj> mySwiftObj_;
- 用法:
mySwiftObj_->someSwiftMethod();
所以这里的问题是,由于循环引用,这些对象没有得到垃圾回收(我尝试并删除了循环引用,它们得到了 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 都没有对它的(强)循环引用,一旦它被释放,其他两个对象也会被释放。