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.