【问题标题】:View coordinator on application startup: should I use View Controller or something else?应用程序启动时的视图协调器:我应该使用视图控制器还是其他东西?
【发布时间】:2019-03-19 17:32:36
【问题描述】:

目前我的应用主界面如下所示:

根视图控制器本身没有任何价值,需要决定显示哪个控制器。逻辑相当复杂,但这对于这个问题并不重要。最简单的类似示例如下所示:

override func viewDidAppear(_ animated: Bool) {

        var controller: UIViewController?

        if !userIsAuthenticated {
            let storyboard = UIStoryboard(name: "Login", bundle: nil)
            controller = storyboard.instantiateViewController(withIdentifier: "loginController")

        }
        else if systemHasAlert {
            let storyboard = UIStoryboard(name: "Alert", bundle: nil)
            controller = storyboard.instantiateViewController(withIdentifier: "alertController")
        }
        else {
            let storyboard = UIStoryboard(name: "Landing", bundle: nil)
            controller = storyboard.instantiateViewController(withIdentifier: "defaultLandingPage")
        }

        guard let _controller = controller else {
            return 
        }

        navigationController?.pushViewController(_controller, animated: true )
}

(逻辑本身是象征性的,不是那么那么简单。但这足以传达这个想法。)

此控制器还为应用程序状态更改时提供稳定的“返回点”。例如用户成功登录后,我需要做的就是:

AppDelegate.shared.navigationController?.popToRootViewController(animated: false)

这会导致 Root View Controller 中的条件被重新评估并且应用程序导航到另一个视图

一般来说这没问题,但我不喜欢 3 件事:

  1. 此根视图暂时可见,这会破坏从一个视图到另一个视图的平滑过渡。我试图通过用viewWillAppear 替换viewDidAppear 来解决它,但在这种情况下似乎根本没有发生导航
  2. 技术上不需要此视图
  3. 在概念层面上,视图控制器充当其他视图的协调器似乎是不对的。

那么有没有更好的选择来提供这样的“根级”协调器?还是根视图协调器是正确的选择,我宁愿担心正确地对其进行样式化,而不是消除它?

提前致谢

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    我不确定我是否理解正确,但您似乎根本不需要根视图控制器,但您需要显示三个控制器之一(即“登录”、“警报”和“ Landing") 应用程序启动时。

    在这种情况下,视图控制器中的viewDidAppear 方法似乎并不是处理此逻辑的最佳位置。最简单的方法是在 application(_:didFinishLaunchingWithOptions:) 方法中的 AppDelegate 类中处理您的逻辑。您的实现可能如下所示:

    
    var window: UIWindow?
    
    ...
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Initialize navigation controller without root view controller
        let navigationVC = UINavigationController()
    
    
        window = UIWindow(frame: UIScreen.main.bounds)
        window?.makeKeyAndVisible()
    
        // Set navigationVC as a root view controller in your application
        // Now it would ignore your storyboard.
        window?.rootViewController = navigationVC
    
        var controller: UIViewController?
    
        if !userIsAuthenticated {
            let storyboard = UIStoryboard(name: "Login", bundle: nil)
            controller = storyboard.instantiateViewController(withIdentifier: "loginController")
    
        }
        else if systemHasAlert {
            let storyboard = UIStoryboard(name: "Alert", bundle: nil)
            controller = storyboard.instantiateViewController(withIdentifier: "alertController")
        }
        else {
            let storyboard = UIStoryboard(name: "Landing", bundle: nil)
            controller = storyboard.instantiateViewController(withIdentifier: "defaultLandingPage")
        }
    
        if let controller = controller {
            navigationVC.pushViewController(controller, animated: false)
        }
    
        return true
    }
    

    P.S.:请记住,上面的实现会覆盖故事板文件中定义的应用程序的入口点。

    P.P.S:您在原始帖子中提到了“协调员”。上面显示的方法是最简单的方法,但可能不是最好的方法。对于更复杂的逻辑,您可能确实需要实现协调器。尽管许多 iOS 开发人员都熟悉协调器的概念,但在 iOS 社区中没有单一的实现方法。因此,我将仅放置几个讨论协调器的链接,希望对您有用:

    1. http://khanlou.com/2015/10/coordinators-redux/
    2. http://khanlou.com/2017/05/back-buttons-and-coordinators/
    3. http://merowing.info/2016/01/improve-your-ios-architecture-with-flowcontrollers/
    4. https://hackernoon.com/coordinators-routers-and-back-buttons-c58b021b32a
    5. https://talk.objc.io/episodes/S01E5-connecting-view-controllers

    【讨论】:

    • 是的,协调器的想法正在流传……甚至我的实现也是一个这样的教程的变体。不幸的是,由于几个原因,我不能使用您的建议。两个重要的是:首先,我还想在应用程序状态更改时重用相同的逻辑,正如我在登录用户的示例中所解释的那样。您提供的第一个链接中提到了另一个重要原因:“Overstuffed App Delegates”是我想避免的。不过还是感谢您的回复!
    • 您可以将AppDelegate 中定义的逻辑放在AppCoordinator 中,它将处理其他协调器(即“LoginCoordinator”、“LandingCoordinator”等)并跟踪应用程序状态的变化。但是,您将需要初始化AppCordinator,我认为除了 AppDelegate 之外没有比这更好的地方了。您可能会将这种情况视为“应用程序代理过多”,但我认为在这种情况下,AppDelegate 内部的逻辑将非常少。
    猜你喜欢
    • 1970-01-01
    • 2017-05-22
    • 1970-01-01
    • 2011-11-23
    • 1970-01-01
    • 1970-01-01
    • 2019-05-31
    • 2014-02-10
    • 2011-06-11
    相关资源
    最近更新 更多