There are two issues here:
As others have pointed out, in general, when you have two or more reference types referring to each other, you need to make one of those references weak to break the strong reference cycle. See Resolving Strong Reference Cycles Between Class Instances.
The more serious problem here is that you have infinite loop. The init of Base is instantiating a new Referenced instance, but the init of Referenced is creating another Base instance (which it’s passing to the Native instance). That new Base instance will then create another Referenced instance, repeating the process, and it will continue doing this until it runs out of memory/stack.
Add print statements inside your various init methods, and you’ll see this infinite loop in action.
You should revisit this model, identify an “ownership” graph. Parent objects can keep strong references to child objects (and possibly instantiate child objects, if appropriate), but child objects should only keep weak references back to their parent objects (and most likely not instantiate new parent objects).
For example, you might do:
class Parent {
var child: Child?
init() {
self.child = Child(parent: self)
}
deinit {
print("deinit called")
}
}
class Child {
weak var parent: Parent?
init(parent: Parent) {
self.parent = parent
}
}
And
func testMe() {
var parent: Parent? = Parent()
parent = nil // in this case, this is unnecessary because `parent` is a local variable, but this is here for illustrative purposes; but note that we don’t have to `nil` the `child`
}
Here, you instantiate a Parent object, which happens to instantiate a child. But note that:
The Parent supplies itself as a parameter to the Child;
The Child only maintains a weak reference back to the Parent; and
The Child obviously does not instantiate a new Parent, but rather just uses the reference that was supplied to it.
You can do a rendition of this with your Native struct, too, but the idea will be the same: Break the strong reference cycle with a weak reference and avoid the infinite loop.
Frankly, in these cases, abstract type names make examples unnecessarily confusing. If you clarify what these various types actual represent with a practical, real-world example, the ownership model will undoubtedly become more self-evident.