繁体   English   中英

Swift-变量初始化闭包中的`self`

[英]Swift - `self` in variable initialization closure

没有lazy关键字的button.addTarget(self, action: #selector(taptap), for: .touchUpInside)工作?

错误地lazy了,并关闭了一个初始化按钮,如下所示:

class MyView: UIView {

    let button: UIButton = {
        let button = UIButton()
        button.addTarget(self, action: #selector(taptap), for: .touchUpInside)
        print(self) // (Function)
        // button.frame = bounds <- Cannot assign here
        return button
    }()

    lazy var button2: UIButton = {
        let button = UIButton()
        print(self) // <sample.MyView ...>
        return button
    }()

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        addSubview(button2)
        addSubview(button)
        button.frame = bounds
        print(self) // <sample.MyView ...>
    }

    @objc func taptap() {
        print("taptap")
    }
}

且打印结果为:

(Function)
<sample.MyView: 0x7f961dd09d80; frame = (67 269; 240 128); autoresize = RM+BM; layer = <CALayer: 0x6080000268a0>>
<sample.MyView: 0x7f961dd09d80; frame = (67 269; 240 128); autoresize = RM+BM; layer = <CALayer: 0x6080000268a0>>
taptap

有什么区别self按钮关闭和self的人? 为什么我的按钮可以使用?

简而言之,当您使用闭包初始化声明实例属性时,该属性将在self可用之前创建(在实例正确初始化之前),因此无法访问self lazy实例属性只能在实例初始化后才能访问,因此您可以从lazy属性访问self

较长版本:

如果通过let button: UIButton = { return UIButton() }()使用闭包初始化,则将在运行时以完全相同的方式处理button变量,就像您像let button:UIButton = UIButton()那样简单地声明它一样。 注意闭包末尾的() 当实例属性被初始化时,这实际上立即执行了闭包,这就是为什么实际上可以将其声明为不可变的原因。 由于实例属性是在调用类初始值设定项之前进行初始化的,因此self在属性的闭包内不可用。

使用lazy关键字声明变量时,仅在首次访问该变量时才对其进行求值。 因此, self在闭包内部可以声明一个lazy属性,因为在创建类实例之前无法访问该属性,因此在所有情况下, self都已经初始化,并且在您访问惰性属性时就可以使用属性。

它可以在NSObject子类中工作,因为NSObject (或更确切地说是NSObjectProtocol )声明了self方法。 该方法在元类型(也是NSObject实例)上也可用,因此您可以在静态上下文中调用它。

它实际上可以在UIButton上运行的事实可能是编译器的一个古怪之处,并且UIButton接受Any? 作为目标。

不要使用它,这不是它的预期工作方式。

看到错误SR-4559

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM