为什么我的 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.
当调用 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.