问题描述
我试图在点击 tabBar 项目时更改 VC 中的标签文本。但是在我将 UINavigationController 嵌入到 VC 之后,我在点击 tabBar 时崩溃了(线程 1:致命错误:在隐式解包可选值时意外发现 nil)。有人知道如何解决吗? This is a photo of crash line
import UIKit
class TabBarController: UITabBarController,UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
func tabBarController(_ tabBarController: UITabBarController,didSelect viewController: UIViewController) {
if tabBarController.selectedindex == 3{
let navVC = tabBarController.viewControllers![3] as? UINavigationController
let bagPageVC = navVC?.topViewController as? bagPage
bagPageVC!.stringCountOfHP = "\(String(bagPageVC!.countArray)) items in bag"
bagPageVC?.tableView.reloadData()
}
}
}
解决方法
这应该可以帮助您的代码避免崩溃,
func tabBarController(_ tabBarController: UITabBarController,didSelect viewController: UIViewController) {
if tabBarController.selectedIndex == 3{
if let navVC = tabBarController.viewControllers?[3] as? UINavigationController,let bagPageVC = navVC.topViewController as? bagPage {
bagPageVC.countOfHP.text = "\(String(bagPageVC.countArray)) items in bag"
}
}
可能有多种原因导致崩溃
1.tabBarController.viewControllers
可能返回 nil,
-
的子类tabBarController.viewControllers![3] as! UINavigationController
虽然在索引 3 处存在视图控制器,但它可能不是UINavigationController
或UINavigationController
-
bagPageVC!可能为零,因此强制解包可能会使其崩溃,因为
navVC.topViewController
不是bagPage
如果不仔细查看您的 ViewController 设置 n 层次结构,就不可能为您提供比这更进一步的帮助。
上面的代码会安全地解开所有的选项,所以它不会让你的代码崩溃
编辑 1:
问题是第一次发生,当您点击索引 3 处的标签栏时,该索引处的 ViewController
尚未在屏幕上可见,因此显然它的所有 IBOutlet
都为零,并且当您盲目访问隐式可选 IBOutlet bagPageVC.countOfHP
它会崩溃。
你能做什么?
我能想到的两种可能的解决方案
解决方案 1:
func tabBarController(_ tabBarController: UITabBarController,didSelect viewController: UIViewController) {
if tabBarController.selectedIndex == 3,let bagPageVC = (viewController as? UINavigationController)?.topViewController as? bagPage {
let _ = bagPageVC.view //this statement will force the view controller to load its view hence `ViewDidLoad` will be called automatically for the first time (which anyway would have called you are just fast tracking it
bagPageVC.countOfHP.text = "\(String(bagPageVC.countArray)) items in bag"
}
}
didSelect viewController
将在每次用户选择不同的标签时被调用,但 let _ = bagPageVC.view
将导致 ViewDidLoad
仅被调用一次(一旦视图被加载,当您访问 .view
它只会返回视图)
虽然这段代码可以正常工作,没有任何问题,但我不是很喜欢干预视图循环,因此解决方案 2
解决方案 2:
检查隐式可选的 IBOutlet
是否为 nil
,如果不是则简单地设置文本,否则将文本传递给 bagPageVC
并将其设置在 ViewDidLoad
func tabBarController(_ tabBarController: UITabBarController,let bagPageVC = (viewController as? UINavigationController)?.topViewController as? bagPage {
if let countLabel = bagPageVC.countOfHP {
countLabel.text = "\(String(bagPageVC.countArray)) items in bag"
}
else {
bagPageVC.countInfo = "\(String(bagPageVC.countArray)) items in bag"
}
}
}
现在在您的 bagPageVC
中声明一个名为 countInfo
的变量为 String?
var countInfo: String? = nil
而在 ViewDidLoad
中,您可以简单地设置
override func viewDidLoad() {
super.viewDidLoad()
countOfHP.text = countInfo
}
ViewDidLoad
在 ViewController 的生命周期中只被调用一次,因此您不必担心在后续的 countInfo
调用中重置 didSelect viewController
你会选择哪一个我留给你:)