#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,
tabBarController.viewControllers![3] as! UINavigationController
Хотя существует контроллер представления с индексом 3, это может быть неUINavigationController
или подклассUINavigationController
- 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. Большое спасибо за помощь. я использовал первый метод в качестве решения.