Reputation: 9009
I'm using Swinject in my Swift iOS app and try doing a circular dependency as explained on the official documentation page: https://github.com/Swinject/Swinject/blob/master/Documentation/CircularDependencies.md
I've copied the code from the circular dependency example and added a few things in the classes, didn't modify anything in the dependency registration code.
Classes and protocols look like this:
protocol ParentType: AnyObject {
func getMyName() -> String
func getMyChildName() -> String
}
protocol ChildType: AnyObject {
func getMyName() -> String
func getMyParentName() -> String
}
class Parent: ParentType {
let child: ChildType?
let name = "John"
init(child: ChildType?) {
self.child = child
}
func getMyName() -> String {
return name
}
func getMyChildName() -> String {
return child!.getMyName()
}
}
class Child: ChildType {
weak var parent: ParentType?
let name = "John Jr."
func getMyName() -> String {
return name
}
func getMyParentName() -> String {
return parent!.getMyName()
}
}
Dependency configuration code looks like this (unchanged from example):
let container = Container()
container.register(ParentType.self) { r in
Parent(child: r.resolve(ChildType.self)!)
}
container.register(ChildType.self) { _ in Child() }
.initCompleted { r, c in
let child = c as! Child
child.parent = r.resolve(ParentType.self)
}
The above code is in my AppDelegate's "application:didFinishLaunchingWithOptions
" function.
Right after the registration code I added this little testing code:
let parent = container.resolve(ParentType.self)!
let child = container.resolve(ChildType.self)!
print(parent.getMyName())
print(child.getMyName())
print(parent.getMyChildName())
print(child.getMyParentName())
The output is this:
John
John Jr.
John Jr.
fatal error: unexpectedly found nil while unwrapping an Optional value
The error occurs on this line:
return parent!.getMyName()
The weird thing is that I placed a breakpoint on that line and this is what happens:
self
, it looks correctly initialised, the parent
property looks correct (a reference to the parent instance)parent
property is nil
Am I doing anything wrong with this circular dependency?
This code is in an "empty" single view iOS app, only with Swinject added as a dependency via Carthage.
XCode version 7.2.1
Swinject version 1.1 installed via Carthage
Upvotes: 3
Views: 2332
Reputation: 4577
The problem is caused because parent
property of Child
is defined as a weak
property.
Let's name the instances like following.
let parentA = container.resolve(ParentType.self)!
let childB = container.resolve(ChildType.self)!
Here the parent of childB
is a different instance from parentA
. Since parent
property of childB
is weak
, it is set to nil
after childB
instance is created.
On the other hand, child
property of Parent
is a strong
property. The instance of the child
of parentA
is different from childB
, but the child
instance is held by parentA
.
If you need the direct access to a child instance, you can add var child: ChildType? { get }
to ParentType
protocol.
Regarding the concept of circular dependency, parentA
's child
's parent
is parentA
, which is the same instance.
If ParentType
is registered as below,
container.register(ParentType.self) { r in
Parent(child: r.resolve(ChildType.self)!)
}
.inObjectScope(.None)
parentA
's child
's parent
and parentA
are different instances.
Upvotes: 1