TabBarController 的第二个选项卡未实例化 -> IBOutlets 为 nil
TabBarController's second tab doesn't get instantiated -> IBOutlets are nil
我正在创建一个简单的应用程序,它有一个选项卡栏控制器,其中摘要是一个选项卡,历史记录是另一个选项卡。在摘要选项卡中,有一个用于添加新回合的按钮。每当添加此回合时,它也必须转到历史选项卡。
我正在尝试通过 tabBarController 发送数据。
我遇到的情况是,每当我在添加新一轮之前不打开历史选项卡时,我的程序就会崩溃,因为我的 IBOutlets 为零。但是每当我先打开选项卡然后返回添加新回合时,它都可以正常工作。我也不必在每一轮之后重新打开选项卡。在我第一次打开它之前,该选项卡似乎没有被实例化。
失败的Gif(错误是图表View
为零):
http://i.imgur.com/VPa0RmK.gifv
成功动图:
http://i.imgur.com/LqxYBjV.gifv
有什么方法可以手动执行此操作吗?
我是 iOS 编程的新手,所以这就是我认为的问题所在。如果发生其他导致我的代码崩溃的事情,我想知道!
它应该是这样工作的。每个选项卡仅在必须显示时才创建。这与 TableViews 和 CollectionViews 的想法相同。
为您解决此问题的简单方法是覆盖 HistoryViewController 的 viewWillAppear(或 viewDidAppear)方法并从那里刷新 UI。
这样,您永远不会假设“历史记录”选项卡存在于“摘要”选项卡中,“历史记录”会自行刷新其 UI。
希望对您有所帮助。
你是对的。问题是第二个选项卡的插座在您访问该选项卡之前不会设置。
解决方案:
您可以将数据写入第二个 viewController 的 属性,然后将该数据移动到覆盖 viewWillAppear
的出口中。
另一种可能性是在写入之前检查插座是否为 nil
。如果是,请在第二个 viewController 上调用 loadView
告诉它设置它的出口,然后你就可以给它们写信了。请注意,如果您手动调用 loadView
,则方法 viewDidLoad
将不会 运行,因此如果您在那里进行任何其他设置,您还需要从 loadView
.
也许比手动调用loadView
更简单的是通过访问view
属性来触发secondViewController的viewDidLoad
。这可以很简单:
if let svc = self.tabBarController?.viewControllers?[1] as? SecondViewController {
// check if outlet is nil
if svc.myLabel == nil {
// trigger viewDidLoad to set up the outlets
_ = svc.view
}
svc.myLabel = "Success!"
}
也就是说,直接访问另一个 viewController 的视图(即插座)是糟糕的设计,并且违反了 MVC(模型-视图-控制器)范例。你真的应该把你的数据放在一个所有选项卡都可以访问的地方,然后在选择选项卡时让每个 viewController 在 viewWillAppear
中更新自己。请参阅此答案:Sharing data in a TabBarController 了解执行此操作的一种方法。
我正在创建一个简单的应用程序,它有一个选项卡栏控制器,其中摘要是一个选项卡,历史记录是另一个选项卡。在摘要选项卡中,有一个用于添加新回合的按钮。每当添加此回合时,它也必须转到历史选项卡。
我正在尝试通过 tabBarController 发送数据。
我遇到的情况是,每当我在添加新一轮之前不打开历史选项卡时,我的程序就会崩溃,因为我的 IBOutlets 为零。但是每当我先打开选项卡然后返回添加新回合时,它都可以正常工作。我也不必在每一轮之后重新打开选项卡。在我第一次打开它之前,该选项卡似乎没有被实例化。
失败的Gif(错误是图表View
为零):
http://i.imgur.com/VPa0RmK.gifv
成功动图: http://i.imgur.com/LqxYBjV.gifv
有什么方法可以手动执行此操作吗?
我是 iOS 编程的新手,所以这就是我认为的问题所在。如果发生其他导致我的代码崩溃的事情,我想知道!
它应该是这样工作的。每个选项卡仅在必须显示时才创建。这与 TableViews 和 CollectionViews 的想法相同。
为您解决此问题的简单方法是覆盖 HistoryViewController 的 viewWillAppear(或 viewDidAppear)方法并从那里刷新 UI。
这样,您永远不会假设“历史记录”选项卡存在于“摘要”选项卡中,“历史记录”会自行刷新其 UI。
希望对您有所帮助。
你是对的。问题是第二个选项卡的插座在您访问该选项卡之前不会设置。
解决方案:
您可以将数据写入第二个 viewController 的 属性,然后将该数据移动到覆盖
viewWillAppear
的出口中。另一种可能性是在写入之前检查插座是否为
nil
。如果是,请在第二个 viewController 上调用loadView
告诉它设置它的出口,然后你就可以给它们写信了。请注意,如果您手动调用loadView
,则方法viewDidLoad
将不会 运行,因此如果您在那里进行任何其他设置,您还需要从loadView
.也许比手动调用
loadView
更简单的是通过访问view
属性来触发secondViewController的viewDidLoad
。这可以很简单:if let svc = self.tabBarController?.viewControllers?[1] as? SecondViewController { // check if outlet is nil if svc.myLabel == nil { // trigger viewDidLoad to set up the outlets _ = svc.view } svc.myLabel = "Success!" }
也就是说,直接访问另一个 viewController 的视图(即插座)是糟糕的设计,并且违反了 MVC(模型-视图-控制器)范例。你真的应该把你的数据放在一个所有选项卡都可以访问的地方,然后在选择选项卡时让每个 viewController 在
viewWillAppear
中更新自己。请参阅此答案:Sharing data in a TabBarController 了解执行此操作的一种方法。