Bra*_*don 4 closures initializer swift swift4
我有以下代码(编辑:更新代码,以便每个人都可以编译并查看):
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
}
}
Run Code Online (Sandbox Code Playgroud)
每次我实例化时TextAlertView,它都会super.init因访问不良而崩溃.但是,如果我改变:
Action(title: "Yes", { [weak self] in
//use self in here..
})
Run Code Online (Sandbox Code Playgroud)
至:
Action(title: "Yes", {
//Blank.. doesn't reference `self` in any way (weak, unowned, etc)
})
Run Code Online (Sandbox Code Playgroud)
有用!
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)
}
Run Code Online (Sandbox Code Playgroud)
更长的答案与参考和东西:
根据文件:
安全检查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)
})
Run Code Online (Sandbox Code Playgroud)
你没有真正捕获self,这就是为什么它被允许并且它有效.但是你没有访问权限self.尝试添加一些使用的代码,self编译器会抱怨:
所以最后,如果你想self在闭包中使用,你将不得不找到一种方法,如何首先调用super.init,只有在self向属性添加捕获闭包之后.