我有以下代码(编辑:更新代码,以便每个人都可以编译并查看):
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)
})
有用!
有没有办法在超级初始化期间引用self
它是否弱于动作块内部(在上面我在super.init
的参数中做它?
代码编译..它只是在运行时随机崩溃。
简短回答:
在self
返回之前,您无法捕获并使用super.init
作为值。在你的情况下,你试图将self
“传递”给super.init
作为参数。
根据为什么第二部分起作用,仅仅因为没有使用self
,它不捕获self
,因此它不使用self
作为值。
如果你不想在闭包中使用self
,那么你不需要担心那里的strong
/ weak
引用,因为那里根本没有引用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)
}
更长的答案与参考和东西:
安全检查4
初始化程序无法调用任何实例方法,读取任何实例属性的值,或者在初始化的第一阶段完成之后将self作为值引用。
第一阶段的初始化是通过调用super.init
来结束的
从相同的文档:
阶段1
在类上调用指定或便利初始化程序。
分配该类的新实例的内存。内存尚未初始化。
该类的指定初始值设定项确认该类引入的所有存储属性都具有值。现在初始化这些存储属性的内存。
指定的初始化程序移交给超类初始化程序,以便为其自己的存储属性执行相同的任务。
这继续了类继承链,直到到达链的顶部。
一旦达到链的顶部,并且链中的最后一个类确保其所有存储的属性都具有值,则认为实例的内存已完全初始化,并且阶段1已完成。
所以只有在调用super.init
之后才允许使用self
作为值:
阶段2
从链的顶部向下工作,链中的每个指定初始化程序都可以选择进一步自定义实例。初始化程序现在可以访问self并可以修改其属性,调用其实例方法等。
最后,链中的任何便利初始化器都可以选择自定义实例并使用
self
。
现在,当你尝试使用self
作为闭包捕获列表中的值时,我并不感到惊讶,它崩溃了。我更惊讶的是编译器允许你这样做 - 现在我想这是一个没有实现错误处理的边缘情况。
在第二种情况:
Action(title: "Yes", {
//Blank.. doesn't reference `self` in any way (weak, unowned, etc)
})
你并没有真正捕获self
,这就是为什么它被允许并且它有效。但是你无法访问那里的self
。尝试添加一些使用self
的代码,编译器会抱怨:
所以最后,如果你想在闭包中使用self
,你将不得不找到一种方法如何首先调用super.init
,然后才添加self
捕获属性的闭包。