在iOS应用中使用ReSwift进行路由(导航)

我一直在与ReSwift合作构建iOS应用。 ReSwift是iOS的redux版本。 这样做的想法是在全局存储区中拥有完整的视图状态。 这样,您的视图便成为状态的函数。 在给定状态的情况下,您知道视图的外观。 从您的角度来看,您将调度一个动作,这是更改状态的唯一方法。 然后,您的视图将根据状态信息重新呈现自己。

在这篇文章中,我想探讨一下我们如何使用ReSwift在我们的应用程序中构建导航流。 如果您想开始使用ReSwift,请仔细阅读ReSwift入门指南以及这篇出色的文章。

当我们研究如何在应用程序内进行路由并通过ReSwift驱动路由时,我们希望基于以下原则构建内容:

我们应该能够从应用程序中的任何位置调度动作,以从一个屏幕移动到任何其他屏幕。

我们想在情节提要上使用Segues来管理过渡。

我们也不想将自己限制为仅使用Segues进行过渡,如果需要进行程序化过渡,那应该是可能的。

所有路由都应从一个中心位置处理,以使其易于调试和维护

在任何时间点,如果我们查看状态,它都应该反映出我们当前所处的确切屏幕。

最好通过一个示例来说明如何使用上述原则对解决方案进行编码:

这是我们正在实施的应用程序:

在情节提要上,它是这样的:

上面的图像总结了解决方案。

您可以使用2个流程从一个屏幕切换到另一个屏幕。

  1. 过渡—这是最简单的流程。 这实质上是将一个屏幕推到导航控制器上,或者模态呈现一个屏幕。 在图中,这是从FirstTabViewController移到Top或BottomViewController的
  2. 重置屏幕层次结构-如果您位于屏幕层次结构内部深深嵌套的屏幕上,并且希望退出屏幕层次结构并转到全新的屏幕层次结构。 在图中,这是从BottomViewController移到SecondTabViewController的。 当您深入链接到应用程序时,这是最需要的。 您可能在应用程序中的任何位置,当您深入链接到应用程序时,您将必须重置屏幕层次结构,并根据深度链接的要求移至新屏幕。 我提供以上示例来说明如何实现重置屏幕层次结构。 理想情况下,您不应该像示例那样拥有用户流,因为这会扼杀用户体验。

所有路由均由AppRouter处理。 有一个由AppDelegate实例化的AppRouter实例,该实例订阅了NavigationState。 接下来,每个发生屏幕切换的视图控制器都具有一个附加的路由器。

当我们需要从一个屏幕移动到另一屏幕时,例如单击“顶部”按钮时,我们将触发类似以下的操作:

这里的Screen是一个枚举,其中包含应用程序上所有可能的屏幕,数据是一个字典,您可以用来传递新屏幕需要呈现的信息。

当转换动作被触发时,NavigationState会更改,并且新状态上有一个名为’transition’的标志设置为true。 此外,转换数据设置为我们要传入的字典。

导航状态更改后,接下来会发生什么? 下图说明了如何触发,进行转换并在显示的新屏幕中达到高潮。

AppRouter侦听对NavigationState的任何更改,然后检查是否设置了过渡标志,如果已设置,则获取当前屏幕的路由器。 在这种情况下,当前显示的屏幕是FirstTabViewController,该视图控制器的相应路由器是FirstTabRouter。 在FirstTabViewController的viewWillAppear中,我们创建FirstTabRouter的新实例,并将其添加到RouterRegistry中,RouterRegistry是[Screen:Router]类型的字典。

AppRouter从NavigationState获取当前屏幕,然后向RouterRegistry查询当前屏幕的路由器。 然后,它在该路由器上调用show()。

路由器现在要做的就是为该屏幕过渡执行segue。

一些解释所有这些的代码:

executeSegueBlock需要一些解释。 当我们要求视图控制器执行segue时,视图控制器将调用prepareForSegue(),它允许您在呈现目标视图控制器之前对其进行配置。 我们在FirstViewRouter中所做的是将一个闭合块传递给executeSequeBlock()调用。 闭包在prepareForSegue()中执行。 这使您可以保持2个代码块,调用segue并准备新屏幕并拢,从而更易于理解和维护。

需要说明的另一点是重置屏幕层次结构。 有时,当您深入链接到应用程序时,或者如果您想要从一个屏幕的层次结构内部的一个屏幕过渡到整个新的屏幕层次结构,那么该怎么做? 例如,如果要从BottomButtonViewController移至SecondTabViewController。


涉及3个步骤:

  1. 我们需要关闭所有屏幕并重置为根视图控制器。 在这种情况下,请返回显示第一个选项卡的TabBarViewController。
  2. 然后,我们需要切换到第二个选项卡。
  3. 然后,从该选项卡中,我们需要显示要显示的任何其他屏幕。

为了完成所有这些操作,我们需要分派另一个操作:

从本质上讲,这意味着,您不必关心当前的屏幕层次结构是什么,您希望应用程序重置为提供的屏幕层次结构,并且设置的数据就是屏幕呈现其自身所需要的。

为了实现这一点,AppRouter首先需要找到负责当前屏幕 层次结构基本路由器。 在此示例中,由于我们位于BottomButtonViewController屏幕上,因此显示此屏幕的选项卡是FirstTabViewController。 该视图控制器负责当前的屏幕层次结构。 与此ViewController关联的路由器是FirstTabRouter。 AppRouter在FirstTabRouter上调用dismissScreens()。 这实际上将在导航控制器上调用popToRootViewController()。 这将完成第一步。

第二步将显示第二个选项卡。 在此示例中,我们到此为止。 但是,如果我们必须在第二个选项卡的顶部显示另一个屏幕,那么我们所要做的就是在SecondTabViewController上执行segue或以编程方式显示我们需要显示的屏幕。

AppRouter看起来像这样:

希望这是有用的。 请在下面留下您的评论和问题。