Swinject的循环依赖问题

时间:2016-03-10 12:04:13

标签: ios swift dependency-injection circular-dependency swinject

我在我的Swift iOS应用程序中使用Swinject并尝试执行循环依赖,如官方文档页面所述:https://github.com/Swinject/Swinject/blob/master/Documentation/CircularDependencies.md

我已经从循环依赖示例中复制了代码,并在类中添加了一些内容,并没有修改依赖注册代码中的任何内容。

类和协议如下所示:

(?1)

依赖关系配置代码如下所示(与示例相同):

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()
    }
}

以上代码位于我的AppDelegate" 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) } "功能。 在注册码之后我添加了这个小测试代码:

application:didFinishLaunchingWithOptions

输出是这样的:

let parent = container.resolve(ParentType.self)!
let child = container.resolve(ChildType.self)!
print(parent.getMyName())
print(child.getMyName())
print(parent.getMyChildName())
print(child.getMyParentName())

此行发生错误: John John Jr. John Jr. fatal error: unexpectedly found nil while unwrapping an Optional value

奇怪的是,我在该行上设置了一个断点,这就是:

  • 代码在断点处停止
  • 我查看return parent!.getMyName(),它看起来正确初始化,self属性看起来正确(对父实例的引用)
  • 我"跳过",发生错误,现在parent属性为parent

我是否对此循环依赖做错了什么?

此代码位于"空"单视图iOS应用程序,仅通过迦太基添加为Swinject作为依赖项。

XCode版本7.2.1

通过Carthage安装Swinject 1.1版

1 个答案:

答案 0 :(得分:1)

问题是由于parent的{​​{1}}属性被定义为Child属性而引起的。

让我们为下面的实例命名。

weak

此处let parentA = container.resolve(ParentType.self)! let childB = container.resolve(ChildType.self)! 的父级是childB的不同实例。由于parentA的{​​{1}}属性为parent,因此在创建childB实例后将其设置为weak

另一方面,nil的{​​{1}}属性是childB属性。 child Parent的实例与strong不同,但child实例由parentA保留。

如果您需要直接访问子实例,可以将childB添加到child协议。

关于循环依赖的概念,parentA' var child: ChildType? { get }' ParentTypeparentA,这是同一个实例。

如果child注册如下,

parent

parentA' ParentType container.register(ParentType.self) { r in Parent(child: r.resolve(ChildType.self)!) } .inObjectScope(.None) parentA是不同的实例。