Пропустить/добавить контроллер просмотра в стеке навигации

У меня есть три контроллера просмотра, встроенных в навигационный контроллер. Я хочу перейти от VC1 к VC3, чтобы в VC3 кнопка назад на навигационном элементе направила пользователя в VC2 вместо VC1. Я думаю, что это должно быть сделано путем добавления VC2 к стеку навигации между VC1 и VC3 при создании VC3 или пропуском второго контроллера просмотра.

Я пробовал это:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if let identifier = segue.identifier {
        switch identifier {
        case "JumpToThirdVCSegue":
            if let secondvc = segue.destinationViewController as? SecondViewController {
                secondvc.performSegueWithIdentifier("ThirdVCSegue", sender: self)
            }
        default: break
        }
    }
}

но я не мог заставить его работать. Возможно, выполнение segue невозможно, если контроллер просмотра еще не открыт?

Каков наилучший способ пропустить контроллер просмотра/добавить контроллер просмотра в середине навигационного стека? Надеюсь, это поможет вам понять, что я пытаюсь сделать:

Ответ 1

Что-то вроде этого должно работать:

    self.navigationController?.pushViewController(viewController2, animated: true)
    self.navigationController?.pushViewController(viewController3, animated: true)

EDIT:

Если вы хотите нажать второй контроллер просмотра, не будучи замеченным пользователем, вам нужно добавить его в контроллер навигации после нажатия третьего контроллера. Это можно сделать, выполнив UINavigationControllerDelegate. Вы можете сохранить свой второй контроллер представления в переменной и вставить его в иерархию контроллеров навигации в методе делегата. Ваш главный контроллер будет выглядеть следующим образом:

class MyViewController: UIViewController, UINavigationControllerDelegate {

    var viewControllerToInsertBelow : UIViewController?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationController?.delegate = self
    }

    func pushTwoViewControllers() {
        if let viewController2 = self.storyboard?.instantiateViewControllerWithIdentifier("id1"),
            let viewController3 = self.storyboard?.instantiateViewControllerWithIdentifier("id2") { //change this to your identifiers
                self.viewControllerToInsertBelow = viewController2
                self.navigationController?.pushViewController(viewController3, animated: true)
        }
    }

    //MARK: - UINavigationControllerDelegate
    func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) {
        if let vc = viewControllerToInsertBelow {
            viewControllerToInsertBelow = nil
            let index = navigationController.viewControllers.indexOf(viewController)!
            navigationController.viewControllers.insert(vc, atIndex: index)
        }
    }

}

Ответ 2

Изменить: с помощью быстрых и segues это должно работать:

override func performSegueWithIdentifier(identifier: String?, sender: AnyObject?) {
    super.performSegueWithIdentifier(identifier, sender: sender);

    if identifier == "JumpToThirdVCSegue" {
        // now the vc3 was already pushed on the navigationStack
        var navStackArray : [AnyObject]! = self.navigationController!.viewControllers
        // insert vc2 at second last position
        navStackArray.insert(viewController2, atIndex: navStackArray.count - 2)
        // update navigationController viewControllers
        self.navigationController!.setViewControllers(navStackArray, animated:false)
    }
}

Таким образом, вы переопределяете performSegueWithIdentifier в VC1, чтобы изменить стек навигации, когда segue для VC3 фактически был выполнен (и не только подготовлен). Это предполагает, что вы хотите обрабатывать эту специальную навигационную логику в VC1.

Ответ 3

Мое решение состояло бы в том, чтобы сохранить свойство BOOL, когда вы должны перейти к третьему, а когда не пропустить, например, объявить shouldSkip в VC2, чтобы, если вы установили его в готовом segue, как показано ниже, вы можете действовать в соответствии с тем, что в VC2

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if let identifier = segue.identifier {
        switch identifier {
        case "JumpToThirdVCSegue":
            secondvc.shouldSkip=true

            }
        default: break
        }
    }
}

а затем в viewDidload VC2 вы должны проверить этот BOOL, и если это правда и выполнить segue, и если не просто перейти вы также можете передавать пропуск, когда этот вид пропуска не требуется

Ответ 4

Существует метод (ссылка), который решает проблему пропуска UIViewController. Просто передайте ему все необходимые UIViewControllers (в навигационном порядке), а последний будет выполнен как текущий активный UIViewController (если он уже не является активным).