2017-06-15 60 views
1

我想填充一個頁面視圖控制器與5個事件,我從API拉。這個想法是,用戶可以瀏覽前5個最新事件並點擊它們以查看關於該事件的更多細節。我遇到的問題是,一旦我得到的事件,我想重新加載視圖控制器的頁面視圖控制器,但是當我嘗試設置視圖控制器時,我收到一個錯誤:fatal error: unexpectedly found nil while unwrapping an Optional value。我爲我的事件數組設置了一個屬性觀察器,所以一旦設置了,我重新加載視圖控制器。這是我的課怎麼樣子:爲什麼我不能在UIPageViewController中設置視圖控制器?

class EventPageViewController: UIPageViewController { 

var eventViewControllers = [EventViewController]() 

var events: [Event] = []{ 
    didSet { 
     self.reloadViewControllers() 
    } 
} 


func reloadViewControllers(){ 

    self.dataSource = nil 
    self.dataSource = self 
    // Get top 5 events 
    let topFiveEvents = Array(events.prefix(5)) 
    print(self.events.count) 
    self.eventViewControllers.removeAll() 
    print(eventViewControllers.count) 

    // Set up view controllers 
    for event in topFiveEvents{ 
     if let controller = self.storyboard?.instantiateViewController(withIdentifier: "event") as? EventViewController{ 
      print(event.title) 
      // Just this line alone is what crashes the app 
      controller.eventTitle.text = event.title 
      self.eventViewControllers.append(controller) 
     } 
    } 

    if self.eventViewControllers.count != 0 { 
     let first = [self.eventViewControllers[0]] 
     self.setViewControllers(first, direction: .forward, animated: false, completion: nil) 

    } 


} 

override func viewDidLoad() { 
    super.viewDidLoad() 
    let timeMin = GTLRDateTime(date: Date()).rfc3339String 
    let params = ["maxResults": "250", 
        "singleEvents": "true", 
        "timeMin": timeMin] 
    NetworkManager.events(forPark: .all, withParameters: params, query: nil) { (events, error) in 
     if error == nil { 
      DispatchQueue.main.async { 
       self.events = events 
      } 
     } 
    } 
} 

override func viewDidLayoutSubviews() { 
    for subView in self.view.subviews { 
     if subView is UIScrollView { 
      subView.frame = self.view.bounds 
     } else if subView is UIPageControl { 
      let pageControl = subView as! UIPageControl 
      pageControl.currentPageIndicatorTintColor = UIColor(red:0.00, green:0.15, blue:0.29, alpha:1.0) 
      pageControl.pageIndicatorTintColor = UIColor(red:0.00, green:0.15, blue:0.29, alpha:0.30) 
      self.view.bringSubview(toFront: subView) 


     } 
    } 
    super.viewDidLayoutSubviews() 
} 



} 

如果我不設置視圖控制器東西然後我得到的頁面視圖控制器,以顯示與靜態信息視圖控制器。我不確定我做錯了什麼。

回答

0

它看起來像我的頁面視圖控制器試圖直接操縱它的子視圖控制器的意見。不要這樣做。

這條線:

controller.eventTitle.text = event.title 

是有可能的原因,假設eventTitle是一個出口。

而是這樣做的,一個字符串屬性添加到您的子視圖控制器:

public var eventTitleString: String 

然後設置改爲:

controller.eventTitleString = event.title 

而在你的子視圖控制器,添加代碼複製那價值到您的領域:

func viewWillAppear(_: animated: Bool) { 
    super.viewWillAppear(animated) 
    eventTitle.text = eventTitleString 
} 

@MrSaturn建議打電話controller.loadViewIfNeeded(),這可能會解決你的崩潰,但這是不好的做法。您應該將視圖控制器的視圖視爲私有視圖,並且絕不會試圖從外部操縱它們。相反,請添加一個公共屬性或函數,以直接更新視圖控制器的視圖。

+0

謝謝,我不知道操縱子視圖控制器視圖是不好的做法,但您的解決方案工作。 – CornWhip

+0

「封裝」原則是面向對象設計的基礎之一。在您設計對象時,請考慮您的對象提供給其他對象的服務的公共「契約」。該部分應該暴露並可供其他對象使用。其他任何東西都應該是私人的,並且不得超出對象本身的範圍。這樣對象對其他對象的實現細節不敏感。只要它們的公共接口保持穩定,內部結構可以按照大或小的方式變化,並且一切仍然有效。 –

+0

如果您創建一個視圖控制器來收集來自用戶的輸入並將其報告給另一個視圖控制器,那麼該視圖控制器應該可以自由切換到使用不同類型的控件或以任何方式向用戶顯示信息。所有它應該被要求做的是具有相同的屬性和方法。當另一個對象直接操縱視圖控制器的視圖時,您將視圖控制器鎖定爲始終以相同的方式實現其視圖。 –

相關問題