2015-12-15 74 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 
    }