应用程序启动时的视图协调器:我应该使用视图控制器还是其他东西?
Posted
技术标签:
【中文标题】应用程序启动时的视图协调器:我应该使用视图控制器还是其他东西?【英文标题】: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 件事:
-
此根视图暂时可见,这会破坏从一个视图到另一个视图的平滑过渡。我试图通过用
viewWillAppear
替换viewDidAppear
来解决它,但在这种情况下似乎根本没有发生导航
技术上不需要此视图
在概念层面上,视图控制器充当其他视图的协调器似乎是不对的。
那么有没有更好的选择来提供这样的“根级”协调器?还是根视图协调器是正确的选择,我宁愿担心正确地对其进行样式化,而不是消除它?
提前致谢
【问题讨论】:
【参考方案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 社区中没有单一的实现方法。因此,我将仅放置几个讨论协调器的链接,希望对您有用:
-
http://khanlou.com/2015/10/coordinators-redux/
http://khanlou.com/2017/05/back-buttons-and-coordinators/
http://merowing.info/2016/01/improve-your-ios-architecture-with-flowcontrollers/
https://hackernoon.com/coordinators-routers-and-back-buttons-c58b021b32a
https://talk.objc.io/episodes/S01E5-connecting-view-controllers
【讨论】:
是的,协调器的想法正在流传……甚至我的实现也是一个这样的教程的变体。不幸的是,由于几个原因,我不能使用您的建议。两个重要的是:首先,我还想在应用程序状态更改时重用相同的逻辑,正如我在登录用户的示例中所解释的那样。您提供的第一个链接中提到了另一个重要原因:“Overstuffed App Delegates”是我想避免的。不过还是感谢您的回复! 您可以将AppDelegate
中定义的逻辑放在AppCoordinator
中,它将处理其他协调器(即“LoginCoordinator”、“LandingCoordinator”等)并跟踪应用程序状态的变化。但是,您将需要初始化AppCordinator
,我认为除了 AppDelegate 之外没有比这更好的地方了。您可能会将这种情况视为“应用程序代理过多”,但我认为在这种情况下,AppDelegate
内部的逻辑将非常少。以上是关于应用程序启动时的视图协调器:我应该使用视图控制器还是其他东西?的主要内容,如果未能解决你的问题,请参考以下文章
应用程序在应用程序启动错误结束时应该有一个根视图控制器 [重复]
IOS:使用 url 方案从浏览器启动应用程序时加载视图控制器?
我在应用程序加载而不是图像时开发启动视频。并且还使用 ios 中的推送视图控制器导航到下一页