Программная навигация через NavigationController-TabBarController-NavigationController

Приложение на основе My Storyboard имеет следующую структуру:

NavigationController (NavCa) -> CollectionViewController (VCa) -> присутствует модально -> TabBarController (TabBarC)

TabBarC имеет две вкладки, каждая из которых встроена в собственный NavigationController:

TabBar [0] NavigationController (NavCTab0) -> TableViewController (VC01) -> ViewController (VC02) -> ViewController (VC03)

TabBar [1] NavigationController (NavCTab1) -> ViewController (VC11) -> ViewController (VC12)

МОЯ ПРОБЛЕМА: одно из моих 3D QuickAction должно переходить непосредственно к VC01.

Я действительно проверял через сайт. Тема Swift: программный переход от одного представления к другому через TabBar и Navigation Controller выглядит очень близко к моему. Я попробовал код (обработчик быстрых действий в AppDelegate.swift):

let mainSB = UIStoryboard(name: "Main", bundle: nil)
let tbc = mainSB.instantiateViewController(withIdentifier: “TabBarC”) as? TabBarController
tbc?.selectedIndex = 0
let ncTab0  = tbc?.viewControllers![0] as! UINavigationController

let vc01 = mainSB.instantiateViewController(withIdentifier: “VC01”) as! TableViewController01
let vc02 = mainSB.instantiateViewController(withIdentifier: “VC02”) as! ViewController02
let vc03 = mainSB.instantiateViewController(withIdentifier: “VC03”) as! ViewController03
let arrayOfVC = [vc01, vc02, vc03]
ncTab0.setViewControllers(arrayOfVC, animated: false)

ncTab0.popToViewController(vc01, animated: true)
self.window?.rootViewController?.present(tbc, animated: true, completion: nil)

но ничего не происходит. В окне вывода ничего не отображается. В приложении ничего не происходит (если приложение было закрыто, оно переходит на экран VCa; если приложение не было закрыто, оно остается на месте до быстрого действия).

Любая помощь высоко ценится.

P.S. Я говорю только по SWIFT.

ИЗМЕНИТЬ

Мой AppDelegate.swift с обработчиком быстрых действий:

class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

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

        var isLaunchedFromQuickAction = false

        // Check if it's launched from Quick Action
        if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem {

            isLaunchedFromQuickAction = true
            _ = handleQuickAction(shortcutItem)
        }

        // Return false if the app was launched from a shortcut, so performAction... will not be called.
        return !isLaunchedFromQuickAction
    }

    func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
        completionHandler(handleQuickAction(shortcutItem))
    }

    func handleQuickAction(_ shortcutItem: UIApplicationShortcutItem) -> Bool {

        var quickActionHandled = false
        let type = shortcutItem.type.components(separatedBy: ".").last!
        if type == "QuickAction1" {
            ... // Navigating to VC01, see piece of code above
            quickActionHandled = true
        }
    }
    return quickActionHandled
}

Тот же обработчик быстрых действий, который я использую в другом своем приложении. Это приложение имеет структуру NavigationController -> ViewController1 -> ViewController2 -> ViewController3. И там также одно из быстрых действий переходит к ViewController2. Работает как часы. Единственное отличие от нового приложения - это структура приложения. Я не могу выиграть навигацию по всем этим TabBarControllers, NavigationControllers и т. Д.

ИЗМЕНИТЬ 2

Как было предложено, я попробовал другой подход к работе с быстрыми действиями из примера кода Apple (https://developer.apple.com/library/content/samplecode/ApplicationShortcuts/Introduction/Intro.html#//apple_ref/doc/uid/TP40016545-Intro-DontLinkElementID_2). И ... Теперь это работает. Частично.

Если я закрою приложение, быстрые действия 3D будут работать нормально.

НО. Если я не закрою приложение и отправлю его только в фоновом режиме - быстрые действия не работают, и в консоли я получаю то же старое сообщение: «Предупреждение: попытка представить‹ APP_NAME.TabBarController: 0x1060b1c00> на ‹UINavigationController: 0x106823200>, вид которого не входит в иерархию окон! '.

Любые идеи?

ИЗМЕНИТЬ 3

КОНЕЧНОЕ РЕШЕНИЕ.

3D Quick Action сделано точно так же, как в примере кода Apple ( https://developer.apple.com/library/content/samplecode/ApplicationShortcuts/Introduction/Intro.html#//apple_ref/doc/uid/TP40016545-IntromentDontLink_2 / a>) В AppDelegate.swift под переключателем shortCutType для быстрого действия с переходом к 'VC01'

case ShortcutIdentifier.first.type:
    // Handle shortcut 1 (static).
    let mainSB = UIStoryboard(name: "Main", bundle: nil)
    let tbc = mainSB.instantiateViewController(withIdentifier: "TabBarC") as? TabBarController
    self.window?.rootViewController?.dismiss(animated: true, completion: nil)
    self.window?.rootViewController?.present(tbc!, animated: true, completion: nil)
    handled = true
    break

Этот код протестирован и работает.


person Евгений М    schedule 14.01.2018    source источник
comment
Если у вас есть обычное приложение на основе StoryBoard, вам не нужно создавать экземпляры собственных контроллеров представления.   -  person ryantxr    schedule 15.01.2018
comment
@ryantxr Продолжайте, пожалуйста. Буду рад увидеть ваше решение.   -  person Евгений М    schedule 15.01.2018
comment
Вы проверили через отладчик, что этот код вообще работает? Было бы полезно увидеть больше вашего AppDelegate. Вы сравнивали свой код AppDelegate с примером приложения Swift ApplicationShortcuts?   -  person ozzieozumo    schedule 15.01.2018
comment
Есть ли у вас переходники для контроллеров навигации?   -  person ryantxr    schedule 15.01.2018
comment
@ozzieozumo Код запущен. У меня нет проблем с другими моими быстрыми действиями 3D. Я бы сказал, что это «стандартная» реализация 3D Quick Action. Проблема в навигации ...   -  person Евгений М    schedule 15.01.2018
comment
Является ли self.window нулевым при запуске этого кода? Если вы развернете его принудительно, произойдет ли сбой приложения?   -  person ozzieozumo    schedule 15.01.2018
comment
@ryantxr В контроллерах навигации нет переходов. 'NavCa' = Начальный контроллер просмотра. И «NavCTab0», и «NavCTab1» связаны с «TabBarC» отношениями.   -  person Евгений М    schedule 15.01.2018
comment
@ozzieozumo self.window = (UIWindow?) 0x0000000105515f70 - ›не ноль. И приложение не давит, когда разворачиваю   -  person Евгений М    schedule 15.01.2018


Ответы (1)


Насколько я понимаю ваш код, я думаю, что достаточно всего трех строк кода.

let mainSB = UIStoryboard(name: "Main", bundle: nil)
let tbc = mainSB.instantiateViewController(withIdentifier: “TabBarC”) as? TabBarController
self.window?.rootViewController.present(tbc, animated: true, completion: nil)

Поскольку контроллеры представления панелей вкладок, похоже, устанавливаются только в раскадровке. и первая вкладка панели вкладок Controller выбрана по умолчанию.

РЕДАКТИРОВАТЬ

Другое решение проблемы «попытка представить ....» вы можете установить флаг и в методе viewDidLoad контроллеров представления вы можете попробовать представить tabBarViewController так же, как в коде.

person Van    schedule 15.01.2018
comment
Полностью согласен с этим упрощением. Однако исходный код тоже должен работать. - person ozzieozumo; 15.01.2018
comment
@Van Я только что проверил ваше предложение. Приложение игнорирует это. И в Консоли я получил предупреждение: Предупреждение: Попытка представить ‹APP_NAME.TabBarController: 0x103080200› на ‹UINavigationController: 0x102826000›, представление которого не находится в иерархии окон! - person Евгений М; 15.01.2018
comment
потому что вы можете вызывать его из appDidfinishlaunchingOptions, где корневое представление еще не на переднем плане. попробуйте ro добавить в applicationDidBecomeActive, но тогда вам нужно будет добавить условие, так как этот метод вызывается все время, даже когда вы возвращаетесь из фона. - person Van; 16.01.2018
comment
rootViewController не является обязательным. Как в вашем коде есть окно? .RootViewController.present .. это должно быть ошибкой компиляции, поскольку вы не разворачиваете rootViewController. Это настоящий код? Можете ли вы показать больше фактического кода AppDelegate, то есть того, где вы вызываете этот код и т. Д. Посмотрите, как в примере приложения ярлыков используется didBecomeActive. Вы делаете то же самое? - person ozzieozumo; 16.01.2018
comment
@ozzieozumo Насчет rootViewController вы абсолютно правы. Постфикс? потерялся здесь. Исправил код в вопросе. - person Евгений М; 17.01.2018
comment
@ozzieozumo Я добавил в вопрос свой код обработчика Quick Action. - person Евгений М; 17.01.2018
comment
@ozzieozumo Спасибо, Ван и ozzieozumo за ваш активный вклад! Я попытаюсь перепрограммировать свой обработчик Quick Action в соответствии с образцом кода Apple developer.apple.com/library/content/samplecode/. Я дам тебе знать. - person Евгений М; 17.01.2018
comment
@ozzieozumo Van & ozzieozumo, пожалуйста, проверьте обновление EDIT 2 до исходного вопроса. - person Евгений М; 18.01.2018
comment
Рад, что ты делаешь успехи. Какое представление видно, когда вы выполняете приложение в фоновом режиме (сценарий, который не работает)? Я думаю (не уверен на 100%), что ваш performActionForShortcut должен будет учитывать возможность того, что панель вкладок уже представлена ​​модально. Если это так, вы можете просто отклонить его, а затем вызвать существующий обработчик ярлыков. Думаю, стоит попробовать. - person ozzieozumo; 18.01.2018
comment
да, согласен с @ozzieozumo, попробуйте отклонить уже представленный контроллер, если таковой имеется, а затем примените быстрое действие. - person Van; 19.01.2018
comment
@ozzieozumo и Ван Ты молодец! В случае перемещения приложения в фоновый режим мне действительно нужно сначала отклонить TabBarController, а затем представить его снова. Теперь это работает. - person Евгений М; 20.01.2018
comment
@ozzieozumo & Van Это такой потрясающий опыт для меня - мне бесплатно помогают люди, которые даже не знают меня. Я очень ценю это. Спасибо, что поделились своими знаниями! - person Евгений М; 20.01.2018