从Swift中的多个ViewControllers收集数据

时间:2018-05-12 06:51:26

标签: ios swift design-patterns architecture cocoa-design-patterns

我有多个viewcontrollers(在导航堆栈中,或者可能没有),每个控制器根据用户输入收集一些数据。最后,我需要在最后一个控制器中使用这些数据。

那么实现这种情况的最佳方法/设计模式是什么?

4 个答案:

答案 0 :(得分:10)

如果您有(导航堆栈)并且需要从所有这些视图控制器收集数据

最佳方式不使用用户默认值或Singleton

对于您的情况,您必须执行视图控制器容器来处理特定的进程。注意( UINavigationControllerUITabBarControllerUISplitViewController *只是容器)

例如创建帐户,需要4个步骤来收集用户输入,每个步骤由ViewController表示,最后您需要将所有这些数据推送到API服务器,

因此,创建子viewControllers的Parent ContainerViewController并使用Delegation在每个步骤之后将数据传递给ParentViewController,ParentViewController将成为允许下一步的领导者并为此步骤提供数据。以下是如何开始创建自己的容器managing-view-controllers-with-container

请勿使用Singleton

可以从应用中的任何位置直接访问单身人士。你无法控制。代码中的很多耦合并使您的对象在将来难以测试

请勿使用UserDefaults

UserDefaults用于存储在应用程序执行之间持续存在的用户首选项。存储在那里的任何内容将一直保留到删除,因此它不是在对象之间传递数据的机制。

所以你将来必须使用架构模式

架构

每个ViewController都应该只关注自己的屏幕。 viewController也不应该彼此了解。如果我们这样做,我们将删除视图控制器类之间的大量耦合。

因此,您可以使用 Coordniator 成为处理所有导航的领导者 Coordniator

并检查如何在MVVM-C

与MVVM集成

Viper也使用此技术来处理导航检查Viper

答案 1 :(得分:1)

嗯,在我看来,最好的方法是使用MVVM(Model-View-ViewModel)架构模式。

1)对于每个UIViewControllers,创建一个单独的类(如果您愿意,从NSObject派生),您认为它是属于该UIViewController的“视图模型”。您的视图控制器不允许访问模型类...现在这是您的“视图模型”类的工作。

2)创建一个名为DependencyManager的单例。您的视图模型访问它以获取您的模型(或者至少是顶级模型,如果它们是分层的)以及它们可能需要的任何其他内容,例如网络服务等... DependencyManager充当您的单元测试可以注入替换的方式“模拟“模型的版本,网络服务等......在测试每个viewModel时。

3)创建包含数据的模型classe。您的视图控制器已在UI控件中收集了各种数据,并将原始数据提供给viewModel。 viewModels可以改变那些数据(或不改变)并将其粘贴到他们从DependencyManager获取的适当模型中。

4)也允许ViewController向viewModel询问数据。因此,您的上一个ViewController将从其viewModel获取所需的任何数据。

请记住:ViewControllers不应直接操作您的模型类。 此外,您的ViewModel永远不应该引用任何UI对象,甚至也不应该引用它的ViewController。

备注:我建议让每个ViewModel符合一个协议,该协议派生自名为“MockableViewModelProtocol”的空协议。您可以将单个属性添加到MockableViewModelProtocol类型的DependencyManager中,以便每个ViewControllers在创建ViewModel之前检查它们,以防单元测试为ViewController分配模拟ViewModel以进行替换。这种协议的另一个好处是快速和快速。清楚地了解ViewModel与其ViewController之间的关系。通常,您不仅具有属性和方法,还具有回调属性(闭包属性)。

所以你去吧。在我看来,这不仅是设计一种在一组viewControllers中管理和访问数据的方法,而且还是测试所有类及其对数据的使用的最佳方法。

与目前声称Storyboards阻止依赖注入并因此阻止对ViewControllers进行测试的说法不同,这只是下铺。通过使用DependencyManager,您的视图控制器测试在那里注入模拟,测试获得了与将模拟直接注入ViewController相同的好处,但ViewController仍然由Storyboard实例化。通过这种方法,我已经非常成功地发布了一个大型应用程序。

答案 2 :(得分:0)

可以通过多种方式实现这一目标,

  1. 沿着控制器传递数据,直到您想要使用它的最后一个。

  2. 使用 Singleton 存储来自每个控制器的数据。 Singleton唯一的问题是它会在你的应用程序中持久存在。

  3. 您还可以将数据存储在 UserDefaults 中。使用数据后,您可以从 UserDefaults 中清除它。

  4. 如果您仍然遇到任何问题,请告诉我。

答案 3 :(得分:0)

在我看来,处理此问题的最佳方法是使用 Flux 设计模式。 github上有一个名为ReSwift的框架,允许单向数据流类似于 Redux

即使您没有专门使用此框架,单向数据流的概念也适用于这种情况。从每个视图控制器收集的状态将存在于任何视图控制器之外,视图控制器将保持彼此不可知,并且不需要任何父视图控制器具有更高级别的协调器。然后在最后一个视图控制器上,访问状态并根据需要使用它。

另一个好处是,如果你需要通过容器将视图控制器分成多个视图控制器,即一个屏幕有2个以上的视图控制器,你不需要创建更多的基础设施来在这些控制器之间传递数据,这在我的经验中得到了真的很乱。