当前位置 : 主页 > 手机开发 > 其它 >

swift – 在super.init中引用self

来源:互联网 收集:自由互联 发布时间:2021-06-11
我有以下代码(编辑:更新代码,以便每个人都可以编译并查看): import UIKitstruct Action{ let text: String let handler: (() - Void)?}class AlertView : UIView{ init(actions: [Action]) { super.init(frame: .zero) for acti
我有以下代码(编辑:更新代码,以便每个人都可以编译并查看):

import UIKit

struct Action
{
    let text: String
    let handler: (() -> Void)?
}

class AlertView : UIView
{
    init(actions: [Action]) {
        super.init(frame: .zero)

        for action in actions {
//            let actionButton = ActionButton(type: .custom)
//            actionButton.title = action.title
//            actionButton.handler = action.handler
//            addSubview(actionButton)
        }
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class TextAlertView : AlertView
{
    init() {
        super.init(actions: [
            Action(text: "No", handler: nil),
            Action(text: "Yes", handler: { [weak self] in
                //use self in here..
            })
        ])
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class MyViewController : UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let alert = TextAlertView()
        view.addSubview(alert)
        self.view = view
    }
}

每次我实例化TextAlertView时,它都会在访问不良的super.init上崩溃.但是,如果我改变:

Action(title: "Yes", { [weak self] in
    //use self in here..
})

至:

Action(title: "Yes", {
    //Blank.. doesn't reference `self` in any way (weak, unowned, etc)
})

有用!

在超级初始化期间有没有办法在动作块中引用自身弱或不弱(在上面我在super.init的参数中做它?

代码编译..它只是在运行时随机崩溃.

简短回答:

在super.init返回之前,您无法捕获并使用self作为值.在你的情况下,你试图将自己“传递”为super.init作为参数.

根据第二部分的工作原理,仅仅因为没有使用自我,它不会捕捉自我,因此它不会将自我用作价值.

如果你不想在闭包中使用self,那么你不需要担心那里的强/弱引用,因为根本没有对self的引用(因为它没有被捕获).没有保留周期的危险.

关于“将自我用作值”的简短说明 – 您可以在赋值的左侧使用self来在初始化时引用self的属性:

let myProperty: String

init(with myProperty: String) {
    // this usage of self is allowed
    self.myProperty = myProperty
    super.init(nibName: nil, bundle: nil)
}

更长的答案与参考和东西:

按照documentation:

Safety check 4

An initializer cannot call any instance methods, read the values of any instance properties, or refer to self as a value until after the first phase of initialization is complete.

第一阶段的初始化是通过调用super.init来结束的

从相同的文档:

Phase 1

A designated or convenience initializer is called on a class.

Memory for a new instance of that class is allocated. The memory is not yet initialized.

A designated initializer for that class confirms that all stored properties introduced by that class have a value. The memory for these stored properties is now initialized.

The designated initializer hands off to a superclass initializer to perform the same task for its own stored properties.

This continues up the class inheritance chain until the top of the chain is reached.

Once the top of the chain is reached, and the final class in the chain has ensured that all of its stored properties have a value, the instance’s memory is considered to be fully initialized, and phase 1 is complete.

因此,只有在调用super.init之后,才允许使用self作为值:

Phase 2

Working back down from the top of the chain, each designated initializer in the chain has the option to customize the instance further. Initializers are now able to access self and can modify its properties, call its instance methods, and so on.

Finally, any convenience initializers in the chain have the option to customize the instance and to work with self.

现在,当你尝试将self用作闭包捕获列表中的值时,我并不感到惊讶,它崩溃了.我更惊讶的是编译器允许你这样做 – 现在我想这是一个没有实现错误处理的边缘情况.

在第二种情况:

Action(title: "Yes", {
    //Blank.. doesn't reference `self` in any way (weak, unowned, etc)
})

你并没有真正捕捉到自我,这就是为什么它被允许并且它有效.但是你没有那里的自我.尝试添加一些使用self的代码,编译器会抱怨:

enter image description here

所以最后,如果你想在闭包中使用self,你必须找到一种方法,首先调用super.init,然后才能在属性中添加自捕获闭包.

网友评论