Swift View和控制器共享变量初始化问题
问题描述:
我将一些代码从Objc移植到Swift。并在Swift的初始化生命周期中挣扎。从简化的角度来看,我试图在这里使用4名玩家:Swift View和控制器共享变量初始化问题
- 一个叫做
Program
的对象。这是我目前主要的顶级模型对象。剩下的3名球员都希望获得他的一个实例。 - A
ProgramEditController
,画在我的Main.storyboard。他负责实例化初始程序,这不能直接作为属性初始化程序完成。 - 顶级自定义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?
,然后把每个地方都放进去/守卫。
答
事实证明,在我最初的处所(通常是这种情况)是一个错误的假设。
UIViewController.init(nib...)
在从界面构建器资产创建时不会调用。但是在接口构建器中链接的局部变量(隐式包装)也不会在init(coder)
的位置设置/实现。正确的做法需要两个调整:
- 移动的
program
VAR的设置到init(coder)
初始化:
例如
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.program = self.site.newProgram()
}
- 转发到在
viewDidLoad()
倍率的图。
例如
override func viewDidLoad() {
super.viewDidLoad()
self.timelineView.program = self.program
}