Swift Lazy 属性 初始化循环引用编译错误?

Swift Lazy Property Initialization Circular Reference Compilation Error?

谁能解释一下为什么下面的代码在编译时会出现循环引用错误?

class Foo {
    
    let closure: ()->()
    
    func someFunc() {}
    
    init(closure: @escaping ()->()) {
        self.closure = closure
    }
}

class Bar {
    
    lazy var foo = Foo { [weak self] in // Circular Reference error here!
        self?.foo.someFunc()
    }
}

但是,如果我将其更改为:

class Bar {

    lazy var foo: Foo = {
        return Foo { [weak self] in
            self?.foo.someFunc()
        }
    }()
}

那么就没有循环引用错误了

我很困惑为什么一个会导致错误,而另一个不会。

已更新:

循环引用在类型推断中:就是foo的类型依赖于self.foo的类型,而self.foo的类型又依赖于foo的类型,这取决于 self.foo 的类型等。

上一个答案:

我想我找到了根本原因(感谢我的一些同事!):

我的同事注意到这段代码编译得很好,这指出它可能是类型推断问题。我被包装闭包弄糊涂了,这显然与真正的问题无关。

class Bar {
    
    lazy var foo: Foo = Foo { [weak self] in
        self?.foo.someFunc()
    }
}

我认为为了让编译器评估 Bar 它必须对 属性 foo 进行类型推断,这需要编译器评估 属性初始化代码。但是 属性 初始化代码本身包含对 self/Bar 的引用,因此为了评估该代码,必须首先评估 Bar。因此循环引用。

问题在这里:

lazy var foo = Foo { [weak self] in
    self.foo.someFunc()
} //     ^^^

所以您是根据 foo 定义 foo。那是一个圆圈。和说

没什么区别
lazy var foo = self.foo

这是很明显的圆形。

当您将整个事物包装在一个评估级别({...}() 构造)时,对 self.foo 的内部引用保证不会被评估,直到稍后。