为什么我的 tableview 出口为零?

Why am I getting nil for tableview outlet?

当调用 TaskListDataSource 的回调时,它会重新加载 todayVC 和 reviewVC,因为它们是 UITableViewController。但是 plannerVC 不是,tableview 属性 是一个出口。

@IBOutlet weak var tableView: UITableView!

为什么当回调运行时它崩溃说它是零。但是,如果我能够以某种方式在页面视图中滚动并查看 plannerVC,它永远不会崩溃,因为 tableview 已加载到内存中。但为什么它一开始不这样做呢?

override func viewDidLoad() {
        super.viewDidLoad()
        let taskListDataSource = TaskListDataSource {
            self.todayVC.tableView.reloadData()
            self.plannerVC.tableView.reloadData()
            self.reviewVC.tableView.reloadData()
        }
        todayVC = storyboard!.instantiateViewController(identifier: "TodayViewController", creator: { coder in
            return TodayViewController(coder: coder, taskListDataSource: taskListDataSource)
        })
        plannerVC = storyboard!.instantiateViewController(identifier: "PlannerViewController", creator: { coder in
            return PlannerViewController(coder: coder, taskListDataSource: taskListDataSource)
        }) 
        reviewVC = storyboard!.instantiateViewController(identifier: "ReviewViewController", creator: { coder in
            return ReviewViewController(coder: coder, taskListDataSource: taskListDataSource)
        })
        addVC = storyboard!.instantiateViewController(identifier: "AddViewController")
        setViewControllers([todayVC], direction: .forward, animated: false)
        dataSource = self
        print(plannerVC.tableView) // Console is printing nil
}

当您调用 instantiateInitialViewController(creator:) 时,UIViewController 已启动,但其 view(以及所有子视图,包括所有 IBOutlet)未加载内存。

所以当你尝试做 self.someIBoutlet(在你的情况下 self.plannerVC.tableView.reloadData(),它崩溃了。

一种解决方案是使用 loadViewIfNeeded() 强制加载视图。 由于加载视图可能很繁重,因此通常在 ViewController 之后不久显示时使用它(例如,在某些 属性 的 didSet 中访问其中的出口,因为它会会立即显示在屏幕上,因此无论如何都会加载视图,只是片刻之后)。

既然您正在加载 3 个 UIViewController,会不会是您没有显示它们,而是过早地加载了它们?
如果是这种情况,您可能会重新考虑您的应用程序架构(您的所有 UIViewController 都不需要初始化并在内存中,也不需要加载它们的视图)。
不过,您可以事先检查视图是否已加载,以及是否可以使用 isViewLoaded.

访问插座

我会在 Planner 中为此添加一个方法VC:

func refreshData() { 
    guard isViewLoaded else { return } 
    tableView.reloadData()
}

旁注,它可能是一个协议(甚至更复杂,比如添加 var tableView { get set },并具有 refreshData() 的默认实现,但那是更进一步的,不是必需的)。 .

protocol Refreshable {
    func refreshData()
}
let taskListDataSource = TaskListDataSource {
    self.todayVC.refreshData()
    self.plannerVC.refreshData()
    self.reviewVC.refreshData()
}

旁注,我会检查是否没有内存保留周期,我会在 TaskListDataSource 的闭包中使用 [weak self],也会将其设为 属性 的 VC.