2015-12-15 68 views
0

我将一些代码从Objc移植到Swift。并在Swift的初始化生命周期中挣扎。从简化的角度来看,我试图在这里使用4名玩家:Swift View和控制器共享变量初始化问题

  1. 一个叫做Program的对象。这是我目前主要的顶级模型对象。剩下的3名球员都希望获得他的一个实例。
  2. A ProgramEditController,画在我的Main.storyboard。他负责实例化初始程序,这不能直接作为属性初始化程序完成。
  3. 顶级自定义UIView子类,名为ProgramTimelineView。在Main.storyboard中绘制,管理各种专业子视图。链接到我的ViewController的属性。还有它的子视图的属性。它希望访问该程序,因此它可以进行布局并将其传递给子视图。
  4. 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 
    } 
} 

我想过会发生:

  1. ProgramEditController.init(nibName...)会先着火。
  2. 超级通话会导致我的ProgramTimelineView.init(coder)触发。
  3. ProgramTimelineView实例将首先调用初始化gridView其设置为一个新的ProgramGridView视图
  4. 的的ProgramTimelineView.init(coder)其余部分将运行,这将增加在GridView到视图树。
  5. 控件将返回到ProgramEditController.init(nibName)初始值设定项。控制器的program属性将被填充。
  6. 装订timelineView将有其program属性集。
  7. ProgramTimelineView将依次设置gridViewprogram属性。

尽管在步骤4和5之间似乎发生了什么,但发生了drawRect()。这会导致seg错误,因为gridView的程序尚未设置!但是为什么现在要发布drawRect()呢?我认为在所有的初始化者都解雇之前这种情况不会发生。但显然有一些副作用正在发生。用什么正确的模式/成语来避免这种情况?我真的不想把所有的program!都变成program?,然后把每个地方都放进去/守卫。

回答

0

事实证明,在我最初的处所(通常是这种情况)是一个错误的假设。

UIViewController.init(nib...)在从界面构建器资产创建时不会调用。但是在接口构建器中链接的局部变量(隐式包装)也不会在init(coder)的位置设置/实现。正确的做法需要两个调整:

  1. 移动的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 
    }