在super.init中引用self [英] Referencing self in super.init

查看:99
本文介绍了在super.init中引用self的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码(编辑:更新了代码,以便每个人都可以编译并查看):

  import UIKit 

结构动作
{
let text:String
let handler:(()-> Void)?
}

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

用于操作中的操作{
//让actionButton = ActionButton(type:.custom)
// actionButton.title = action.title
// actionButton.handler = action.handler
// addSubview(actionButton)
}
}

是否需要初始化?(编码器aDecoder:NSCoder){
fatalError( init(编码器:)尚未实现)
}
}

类TextAlertView:AlertView
{
init(){
super。 init(actions:[
Action(text: No,handler:nil),
Action(text: Yes,handler:{[weak self] in
//使用self (
})
])
}

是否需要init?(编码器aDecoder:NSCoder){
fatalError( init(coder: )尚未实施)
}
}

类MyViewController:UIViewController {
覆盖func viewDidLoad(){
super.viewDidLoad()

let alert = TextAlertView()
视图。 addSubview(alert)
self.view =查看
}
}

每次我实例化 TextAlertView 时,它都会在 super.init 崩溃且访问不正确。但是,如果我更改:

  Action(title: Yes,{[weak self] in 
//在这里使用self ..
})

至:

  Action(title:是,{
//空白..不会以任何方式引用 self(弱,无人,等等)
})

它有效!



是否可以在超级初始化期间引用 self 是弱还是不在动作块内(在上面,我在 super.init



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

解决方案

简短答案


您无法捕获和使用 self 作为 super.init 返回之前的值。您的情况是,您试图传递 self super.init 作为参数。


根据为什么第二部分工作,只是因为没有usi ng self ,它不会捕获 self ,因此它不使用 self 作为值。


如果您不想在闭包中使用 self ,则不要那里不必担心 strong / 的引用,因为这里没有对的引用自我在那里(因为它未被捕获)。没有保留周期的危险。




关于使用 self 作为值的简短说明。 -您可以在作业左侧使用 self 来初始化 self 的属性:

  let myProperty:字符串

init(with myProperty:String){
//这种用法
self.myProperty = myProperty
super.init(nibName:nil,bundle:nil)
}




参考文献和内容较长的答案


根据


最后,如果要在闭包中使用 self ,则必须找到一种方法首先调用 super.init ,然后再添加 self 捕获闭包的属性。


I have the following code (EDIT: Updated the code so everyone can compile it and see):

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

Everytime I instantiate TextAlertView, it crashes on super.init with bad access. However, if I change:

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

to:

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

it works!

Is there a way to reference self be it weak or not inside the action block during a super initialization (in the above I do it in a parameter to super.init?

The code compiles.. it just crashes at runtime at random.

解决方案

Short answer:

You cannot capture and use self as a value before super.init returns. In your case, you are trying to "pass" self to super.init as an argument.

As per why the second part works, simply because without using self in it, it does not capture self, thus it does not use self as a value.

If you don't want to use self in the closure, then you don't need to worry about strong/weak reference there, because there is no reference to self there at all (since it was not captured). No danger of retain cycle.


Short sidenote about "using self as a value" - you can use self on the left-hand side of an assignment to refer to properties of the self when initializing them:

let myProperty: String

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


Longer answer with references and stuff:

As per 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.

First phase of initialization is ended by calling super.init, when the

From the same documentation:

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.

So only after calling super.init you are allowed to use self as value:

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.

Now I am not surprised at all that when you try to use self as a value in a capture list of the closure, that it crashes. I am more surprised that the compiler does allow you to do it - now I guess it's an edge case for which error handling wasn't implemented.

In the second case:

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

You don't really capture self, that's why it is allowed and it works. But you don't have access to self there. Try to add there some code that uses self and the compiler will complain:

So in the end, if you want to use self in the closure, you will have to find a way how to first call super.init and only after that add self capturing closures to the properties.

这篇关于在super.init中引用self的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆