Как подключить VC throw NavController в TabBarController для передачи данных в swift

#ios #swift #uiviewcontroller #uinavigationcontroller #uitabbarcontroller

#iOS #swift #uiviewcontroller #uinavigationcontroller #uitabbarcontroller

Вопрос:

Я пытаюсь изменить текст метки в VC при нажатии элемента TabBar. Но после того, как я внедрил UINavigationController в VC, у меня сбой при нажатии на панель вкладок (поток 1: Фатальная ошибка: неожиданно найдено nil при неявном развертывании необязательного значения). Кто-нибудь знает, как это исправить? Это фотография строки сбоя

 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()
            
        }
        
    }
}
 

Комментарии:

1. либо let bagPageVC = navVC.topViewController as? bagPage или tabBarController.viewControllers![3] as! UINavigationController это должно быть возвращено nil , добавьте if let или guard let для дальнейшей отладки

Ответ №1:

Это должно помочь вашему коду избежать сбоев,

     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, это может быть не UINavigationController или подкласс UINavigationController
  2. bagPageVC! может быть nil и, следовательно, принудительное разворачивание может привести к сбою, потому navVC.topViewController что это не bagPage

Без надлежащего изучения вашей иерархии ViewController set up 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, 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, поэтому вам не нужно беспокоиться о сбросе countInfo при последующем didSelect viewController вызове

Какой из них вы выберете, я оставляю это вам 🙂

Комментарии:

1. он разбился. я попытался распечатать bagPageVC, он напечатал правильный VC

2. Произошел ли сбой даже после использования этого кода? Можете ли вы добавить скриншот сбоя

3. я добавил скриншот к вопросу

4. Сбой четко показывает, что ваша countOfHP метка равна нулю, это IBOutlet? Правильно ли он подключен? IBOutlet может быть равен нулю, если он не подключен к UIComponent в storyboard или если пользовательский интерфейс еще не загружен, но если это один из контроллеров панели вкладок view controller, я считаю, что viewDidLoad уже вызывается для всех ViewControllers, поэтому единственная оставшаяся возможность — IBOutlet не подключен

5. Большое спасибо за помощь. я использовал первый метод в качестве решения.