我正在将一些代码从Objc移植到Swift。并与Swift的初始化生命周期挣扎。从简化的角度来看,我试图在这里发挥4个球员:
Program
的对象。这是我此时的主要顶级模型对象。其余3名玩家都想要访问他的一个实例。ProgramEditController
,画在我的主Main.storyboard中。他负责实例化一个初始程序,该程序无法直接作为属性初始化程序完成。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)
开火。gridView
初始值设定项,将其设置为新的ProgramGridView
视图ProgramTimelineView.init(coder)
的剩余部分将运行,这会将gridView添加到视图树中。ProgramEditController.init(nibName)
初始值设定项。将填充控制器的program
属性。timelineView
将设置program
属性。ProgramTimelineView
会依次设置program
的{{1}}属性。在步骤4和步骤5之间似乎发生的事情是gridView
发生了。这会导致seg故障,因为gridView的程序还没有设置好!但是为什么在这一点上发布drawRect()呢?我认为在所有初始化程序都被解雇之前不会发生这种情况。但显然有一些副作用正在发生。使用什么样的正确模式/成语来避免这种情况?我真的不想把所有的drawRect()
变成program!
,然后把let / guard放在每个地方。
答案 0 :(得分:0)
在我原来的场所(通常是这种情况),结果证明是错误的假设。
从界面构建器资产创建时,不会调用 from sklearn import datasets
import pandas as pd
tmp = datasets.load_iris()
iris = pd.DataFrame(tmp.data, columns=tmp.feature_names)
iris['species'] = tmp.target_names[tmp.target]
iris.species = iris.species.astype('category')
import seaborn as sns
import matplotlib.pyplot as plt
sns.set_style('darkgrid')
sns.boxplot(x='species', y='sepal length (cm)', data=iris_new)
plt.show()
。但是在接口构建器中链接的局部变量(隐式包装)也不会在UIViewController.init(nib...)
处设置/实现。正确的方法需要两个调整:
init(coder)
var的设置移至program
初始值设定项:e.g。
init(coder)
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.program = self.site.newProgram()
}
覆盖中的视图。e.g。
viewDidLoad()