如何连接VC throw navController in tabBarController to pass data in swift

How to connect VC throw navController in tabBarController to pass data in swift

我正在尝试在点击 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 可能是 returning nil,

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

    的子类
  2. bagPageVC!可能为零,因此强制解包可能会使它崩溃,因为 navVC.topViewController 不是 bagPage

如果不仔细检查您的 ViewController 设置 n 层次结构,就不可能为您提供比这更进一步的帮助。

上面的代码将安全地解包所有可选值,因此不会使您的代码崩溃

编辑 1:

问题第一次发生,当你点击索引 3 处的标签栏时,该索引处的 ViewController 在屏幕上还不可见,所以显然它的所有 IBOutlet 都是零,当您盲目访问隐式可选 IBOutlet bagPageVC.countOfHP 它崩溃。

你能做什么?

我能想到的两种可能的解决方案

解决方案一:

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 它只会 return 视图)

虽然这段代码绝对可以正常工作,没有任何问题,但我不太喜欢干预 View 循环,因此采用解决方案 2

方案二:

检查隐式可选 IBOutlet 是否为 nil,如果不是则简单地设置文本,否则将文本传递给 bagPageVC 并在 [=25= 中设置]

func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
        if tabBarController.selectedIndex == 3,
           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的生命周期中只被调用一次,所以不用担心在后续的didSelect viewController调用中重置countInfo

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