2017-06-15 93 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

如果您创建一个视图控制器来收集来自用户的输入并将其报告给另一个视图控制器,那么该视图控制器应该可以自由切换到使用不同类型的控件或以任何方式向用户显示信息。所有它应该被要求做的是具有相同的属性和方法。当另一个对象直接操纵视图控制器的视图时,您将视图控制器锁定为始终以相同的方式实现其视图。 –

相关问题