UITabBarItem в приложении Xcode имеет фатальную ошибку, поскольку обнаружен nil при неявном разворачивании необязательного значения. Не уверен, что не так / как исправить - PullRequest
0 голосов
/ 16 июня 2020

Изменить: Не уверен, что могу отметить вопрос как решенный, но это было благодаря Алексу. Это была проблема с последней версией Xcode, но инструкции предназначались для более старой. Перенос фрагментов кода из AppDelegate в SceneDelegate исправил это.

Я новичок в разработке приложений Xcode и IOS. Я прохожу свой первый курс, и мы получаем «практические занятия», в которых мы следуем пошаговым инструкциям и копируем и вставляем фрагменты кода для создания приложения. Следуя инструкциям, я застрял в определенном месте и безуспешно пытался поискать в Google / поискать информацию.

Приложение называется Ресторан и по сути позволяет пользователю просматривать меню (см. Элементы / цены / подробности) и добавлять определенные элементы в заказ, который затем отображается на другой вкладке под названием «Ваш заказ». Эти части были выполнены, но мой шаг - «обновить значение значка на вкладке« Заказ », чтобы оно соответствовало количеству элементов в заказе. Затем пользователь может увидеть, что они успешно добавили элемент без необходимости переключения вкладки ". UITabBarItem является необязательным, как указано в инструкциях внутри AppDelegate, но равен нулю.

Эта строка вызывает ошибку: Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

Похоже, что след ошибки происходит из updateOrderBadge(), в частности, из-за корректировки orderTabBarItem, являющейся основной проблемой. Комментируя эту единственную строку, все работает, хотя, конечно, я не получаю желаемого уведомления о значке. Не уверен, почему в той строке, которая идет непосредственно из руководства, возникают проблемы:

@objc func updateOrderBadge() {
        orderTabBarItem.badgeValue = String(MenuController.shared.order.menuItems.count)
    }

Я видел эту или аналогичную ошибку раньше, когда забыл подключить IBOutlets / Actions от кнопки к коду, предполагается ли быть чем-то вроде этого для UITabBarItem?

Для некоторого общего контекста вот инструкции и код на снимках экрана:

Снимок экрана с конкретными c лабораторными инструкциями, которые, как я думал, я выполнил шаг за шагом шаг / копирование и вставка напрямую enter image description here

Снимок экрана раскадровки для контекста enter image description here

Код внутри AppDelegate, что я изменение enter image description here

В противном случае вот код в делегате приложения в тексте:

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var orderTabBarItem: UITabBarItem!

    @objc func updateOrderBadge() {
        orderTabBarItem.badgeValue = String(MenuController.shared.order.menuItems.count)
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        window = UIWindow()
        orderTabBarItem = (self.window?.rootViewController as? UITabBarController)?.viewControllers?[1].tabBarItem

        NotificationCenter.default.addObserver(self, selector: #selector(updateOrderBadge), name: MenuController.orderUpdatedNotification, object: nil)

        return true
    }

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {

        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {

    }

}

Ответы [ 2 ]

1 голос
/ 16 июня 2020

Похоже, что вы используете Xcode 11 для своего проекта, поэтому у вас есть файл SceneDelegate.swift в вашем проекте и методы, связанные с UIScene, в вашем AppDelegate.swift файле.

По умолчанию шаблон в Xcode 11 использует SceneDelegate и все связанные методы, которые поставляются с iOS 13, поэтому процесс запуска приложения сильно отличается от процесса в iOS 12.

In iOS 13, window больше не является свойством AppDelegate, но вместо этого по умолчанию управляется SceneDelegate.

Я думаю, что проект курса, которому вы сейчас следуете, имеет были созданы с помощью более ранней версии Xcode, поэтому они просят вас добавить свойство window в AppDelegate и инициализировать его методом didFinishLaunchingWithOptions, и проблема в том, что это неправильный способ сделать это больше в iOS 13.

Короче говоря, по умолчанию делегат приложения теперь использует конфигурацию сцены по умолчанию, а делегат сцены отвечает за установку объекта UIWindow через метод делегата scene(_:willConnectTo:options:) . По умолчанию он использует Main.storyboard для создания вашего первого экрана.

В вашем случае для решения вашей проблемы вам просто нужно будет получить доступ к свойству window из метода делегата scene(_:willConnectTo:options:) объекта SceneDelegate вот так:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?
    var orderTabBarItem: UITabBarItem!

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let _ = (scene as? UIWindowScene) else { return }
        orderTabBarItem = (self.window?.rootViewController as? UITabBarController)?.viewControllers?[1].tabBarItem
    }

    // ...
}

Если вы хотите сделать свой проект совместимым и с iOS 12 (и сохранить свойство окна в AppDelegate), вы также можете это сделать, но я бы не стал рекомендую.

В любом случае, вы можете найти более интересную информацию по ссылке ниже, которая показывает разницу между старым процессом запуска и новым процессом, и, что более важно, объясняет, как вы можете настроить новый процесс запуска в iOS 13, независимо от того, решите ли вы использовать Раскадровки или нет:

https://learnappmaking.com/scene-delegate-app-delegate-xcode-11-ios-13/#using -scene-delegate-with-storyboards

Не стесняйтесь спросить, можете ли вы все еще есть сомнения, и удачи в вашем курсе :)

1 голос
/ 16 июня 2020

Похоже, вы пропустили шаг инициализации window. Попробуйте инициализировать окно внутри метода didFinishLaunchingWithOptions. Также добавьте наблюдателя после установки orderTabBarItem. Как это:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    window = UIWindow()
    if let tabBarController = window?.rootViewController as? UITabBarController {
        if let tabBarItem = tabBarController.viewControllers?[1].tabBarItem {
            orderTabBarItem = tabBarItem
            print("Successfully set orderTabBarItem")
        } else {
            print("TabBarController didn't have any viewControllers")
        }
    } else {
        print("rootViewController isn't a UITabBarController")
    }

    NotificationCenter.default.addObserver(self, selector: #selector(updateOrderBadge), name: MenuController.orderUpdatedNotification, object: nil)

    return true
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...