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

问题描述

谁能解释为什么下面的代码在编译时会导致循环引用错误

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

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

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

解决方法

问题在这里:

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

所以您是根据 foo 定义 foo。那是一个圆圈。跟说没区别

lazy var foo = self.foo

很明显是圆形的。

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

,

更新:

循环引用在类型推断中:foo的类型取决于self.foo的类型,foo的类型取决于self.foo的类型,而class Bar { lazy var foo: Foo = Foo { [weak self] in self?.foo.someFunc() } } 的类型取决于Bar 的类型等。

上一个答案:

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

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

foo

我认为为了让编译器评估 self,它必须对属性 Bar 进行类型推断,这需要编译器评估属性初始化代码。然而,属性初始化代码本身包含对 Bar/template<class Float> struct Number { Float v; Number(Float iv = 0) : v(iv) {} }; template<class F> Number<F> operator+(Number<F> const& a,Number<F> const& b) { return {a.v + b.v}; } int main() { Number<float> y = Number<float>(1) + 2.0f; std::cout << y.v << "\n"; } 的引用,因此为了评估该代码,必须首先评估 main.cpp:15:38: error: invalid operands to binary expression ('Number<float>' and 'float') Number<float> y = Number<float>(1) + 2.0f; ~~~~~~~~~~~~~~~~ ^ ~~~~ main.cpp:10:11: note: candidate template ignored: could not match 'Number<type-parameter-0-0>' against 'float' Number<F> operator+(Number<F> const& a,Number<F> const& b) { ^ 。因此循环引用。