【发布时间】:2015-12-15 00:53:44
【问题描述】:
我正在将一些代码从 Objc 移植到 Swift。并在 Swift 的初始化生命周期中苦苦挣扎。从简化的角度来看,这里有 4 名球员我想发挥作用:
- 名为
Program的对象。这是我此时的主要顶级模型对象。其余 3 名玩家都想访问他的一个实例。 - 一个
ProgramEditController,画在我的主Main.storyboard中。他负责实例化一个初始 Program,这不能作为属性初始化器直接完成。 - 顶级自定义 UIView 子类,称为
ProgramTimelineView。绘制在 Main.storyboard 中,管理各种专门的子视图。链接到我的 ViewController 的属性。也有它的子视图的属性。它想要访问程序,因此它可以进行布局并将其传递给子视图。 -
ProgramTimelineView的特定子视图称为ProgramGridView。这些不是在 XCode 画布工具中绘制的,而是直接由包含的ProgramTimelineView实例化的。它想要访问该程序。用它来做他的自定义drawRect。
这是我的控制器的相关代码:
class ProgramEditController: UIViewController {
// MARK: - Variables
@IBOutlet var timelineView:ProgramTimelinesView!
var site = Site()
var program:Program!
// MARK: - Initialize
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
// set up the new program
self.program = self.site.newProgram()
// get it into our top view before it starts drawing
self.timelineView.program = self.program
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder) // Why does Swift make me have a redundant thing here?
}
}
对于 ProgramTimelinesView:
class ProgramTimelinesView: UIView {
// MARK: - Variables
var gridView = ProgramGridView()
var program:Program! {
didSet {
self.gridView.program = self.program
}
}
// MARK: - Initialization
func addGridView() {
self.gridView.alpha = 0.0
self.gridView.opaque = false
self.addSubview(self.gridView)
}
func commonInit() {
self.addGridView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.commonInit()
}
}
最后是ProgramGridView:
class ProgramGridView: TimeAxisView {
// MARK: - Variables
var program:Program!
override func drawRect(rect: CGRect) {
// access self.program in here
}
}
我认为会发生的事情:
-
ProgramEditController.init(nibName...)会先触发。 - 超级调用会导致我的
ProgramTimelineView.init(coder)触发。 - ProgramTimelineView 实例将首先调用
gridView初始化程序,将其设置为新的ProgramGridView视图 -
ProgramTimelineView.init(coder)的其余部分将运行,这会将 gridView 添加到视图树中。 - 控制将返回到
ProgramEditController.init(nibName)初始化程序。控制器的program属性将被填充。 - 绑定的
timelineView将设置其program属性。 -
ProgramTimelineView将依次设置gridView的program属性。
不过,在第 4 步和第 5 步之间似乎发生了drawRect()。这会导致 seg 错误,因为尚未设置 gridView 的程序!但为什么此时要发出 drawRect() 呢?我认为在所有初始化程序都被触发之前不会发生这种情况。但很明显,一些副作用正在发生。避免这种情况的正确模式/习语是什么?我真的宁愿不要把所有的program! 变成program? 然后把 let/guards 放在每个地方。
【问题讨论】:
标签: swift uiview uiviewcontroller initialization swift2