如何连接 VC 在 tabBarController 中抛出 navController 以快速传递数据

问题描述

我试图在点击 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,

  1. tabBarController.viewControllers![3] as! UINavigationController 虽然在索引 3 处存在视图控制器,但它可能不是 UINavigationControllerUINavigationController

    的子类
  2. 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

你会选择哪一个我留给你:)