Как найти вызывающий viewController в моем стеке? - PullRequest
0 голосов
/ 29 мая 2020

У меня есть приложение с двумя раскадровками, одним контроллером панели вкладок и 6+ контроллерами просмотра, встроенными в их собственные контроллеры навигации.

Я представляю CartViewController модально из barButtonItem во всех V C и из корзину представляю CustomersV C из таблицыViewCell. Моя проблема в том, что когда я представляю клиентов из корзины, я могу снова go в корзину из клиентовV C, а затем просто продолжать входить l oop ..

предположение

Мое предположение состоит в том, что если я представляю Cart модально из anyV C, а затем представляю NavigationController модально из корзины, который затем представляет CustomersV C, массив хотел бы, чтобы это существовало:

  1. Any viewController
  2. CartViewController
  3. CustomersNavigationController
  4. CustomersViewController

Чтобы исправить это, я пытаюсь удалить элемент barButtonItem «ViewCart» из customersV C ЕСЛИ вызывается из корзины. Моя проблема в том, что я не могу пройти по стеку, чтобы проверить его. Я опробовал несколько методов, найденных здесь, в SO, но ни один из них не работает.

Я знаю, что могу использовать делегата и установить переменную для отображения / скрытия кнопки, но я очень хочу научиться, а также хотелось бы, чтобы он был более надежным, вместо того, чтобы не забывать устанавливать и сбрасывать переменную вручную.

Есть предложения?

Код


extension UIViewController {
    @objc func viewCart() {
        if Cart.sharedInstance.order.items.count != 0 {

            let storyboard = UIStoryboard(name: "Cart", bundle: nil)
            if let cartVC = storyboard.instantiateViewController(withIdentifier: "Cart") as? CartViewController {
                let cartNavigationController = UINavigationController(rootViewController: cartVC)
                self.present(cartNavigationController, animated: true)
            }
        }
    }
}

Class CartViewController {

  let storyboard = UIStoryboard(name: "Main", bundle: nil)
   if let customersNC = storyboard.instantiateViewController(withIdentifier: "CustomersNC") as? UINavigationController {
   present(customersNC, animated: true)

}


class CustomersTableViewController {

override func viewDidLoad() {

// Tried presentingViewController:

    if let CartVC = presentingViewController as? CartViewController {
        myButton.isEnabled = false
    }

// Tried navigationController?.viewControllers:

        guard let controllersInStack = navigationController?.viewControllers else { return }
        if let CartVC controllersInStack.first(where: { $0 is CartViewController }) as? CartViewController  {
            myButton.isEnabled = false
        }

// Tried an extension I found here https://stackoverflow.com/questions/38583941/get-all-list-of-uiviewcontrollers-in-ios-swift, but it returns nil

extension UIViewController {
   /**
    * Traverses the entire VC hirearchy downwards and collects VC'w that are of speccific PARAM: type
    * - Fixme: ⚠️️ this can be written more elegantly with flatMap
    * ## Example:
    * let vc: CustomVC? = UIApplication.shared.delegate?.window?.rootViewController?.descendants().first
    */
   func descendants<T>(type: T.Type? = nil) -> [T] {
       var childrenOfType: [T] = []
       self.children.forEach {
           if let child: T = ($0 as? T) {
               childrenOfType.append(child)
           }
           if !$0.children.isEmpty {
               childrenOfType += $0.descendants(type: type)
           }
       }
       return childrenOfType
   }
}

1 Ответ

1 голос
/ 29 мая 2020

Каждый контроллер представления имеет либо parent, либо presentingViewController (или оба), поэтому, запросив их, вы можете выяснить, «где вы находитесь».

Обычно этого достаточно, чтобы рассказать вам о ситуации, особенно если вы разумно используете типы классов (например, вы можете сделать свои контроллеры навигации разными подклассами UINavigationController только для того, чтобы знать, где вы находитесь позже).

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

func trace(_ vc: UIViewController) {
    print(vc)
    if let parent = vc.parent {
        print("parent:")
        trace(parent)
        return
    }
    if let presenter = vc.presentingViewController {
        print("presenter:")
        trace(presenter)
        return
    }
    print("done")
}

Этот пример печатает, а не накапливает список контроллеров представления вместе с характером соединения между каждым из них (что вам действительно нужно), но, вызвав его из «последнего» контроллера представления в цепочке, вы можете получить мысленное представление о том, как цепочка должна выглядеть в той точке, где вы хотите сказать: « go не глубже ".

Вот более полный пример, который показывает, как накапливать ab обратная трассировка в массив:

class MyVC: UIViewController {
    func makeTrace() {
        super.viewDidAppear(animated)
        let result = self.trace([(.start, self)])
        print(result)
    }
    enum Link: String {
        case parent
        case presenter
        case start
    }
    typealias Chain = [(Link, UIViewController)]
    func trace(_ chain: Chain) -> Chain {
        if let parent = chain.last!.1.parent {
            return trace(chain + [(.parent, parent)])
        }
        if let presenter = chain.last!.1.presentingViewController {
            return trace(chain + [(.presenter, presenter)])
        }
        return chain
    }
}

Итак, result скажет вам достаточно, чтобы знать, «где вы находитесь».

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