【发布时间】:2018-07-27 08:43:35
【问题描述】:
附注:
这不是一个自以为是的问题。在 VIPER 中连接各种模块是一个合理的疑问。这是一个理论问题,所以没有附加代码。我只需要知道在这种特定情况下我们如何连接 View-Presenter-Router 而不会违反VIPER 的基本规则
我是第一次尝试亲身体验 VIPER。这是我对VIPER的基本理解。
视图:应该显示 UI 控件并捕获 IBActions 并调用其演示者的委托方法来处理事件
Presenter:将处理所有与 UI 相关的数据并准备数据以进行渲染并将数据交还给 View。每当需要屏幕转换时,它都会调用其路由器并要求路由器执行转换
P.S: Presenter 中不会有任何 UIComponents。所以演示者中没有import UIKit 声明。
Router:负责执行屏幕转换,通常借助线框来完成(可选但在应用中有这样的类很好)
Interactor:包含所有业务逻辑。Presenter会在需要基于业务逻辑进行处理时调用Interactor。
实体: POJO 类(简单的 Swift 对象或核心数据实体)。
现在问题来了:
如果我的假设是正确的,Presenter 应该是一个没有UIKit 访问权限的普通 Swift 类。
如果为真,假设我按下我的ViewControllerA 上的一个按钮,我需要在其上按下另一个ViewControllerB,显然ViewControllerA 将与PresenterA 对话并告诉它该按钮已被点击,现在@ 987654329@ 应该与RouterA 交谈并告诉它推送ViewControllerB。
因为路由器可以访问UIKit,我可以使用storyboard 实例或xib 轻松创建ViewControllerB 的新实例,但为了推送该实例,我需要ViewControllerA 的实例。
但是PresenterA 不能包含对ViewControllerA 的引用,或者可以在函数中作为参数传递给PresenterA,因为UIViewController 属于UIKit,并且Presenter 不应该有UI 语句。
我能想到的可能解决方案:
解决方案 1:
在创建路由器实例时,将相应的ViewController 实例作为其初始化(依赖注入阶段)的一部分传递,这样路由器将始终引用它所属的 ViewController
解决方案 2:
让路由器声明它的协议并在 ViewController 中实现它,并且每当需要引用 ViewController 时使用路由器的委托。但这与 VIPER 的规则相矛盾,即路由器不应该与 View 通信。
我的想法是正确的吗?我的假设是否正确?如果是,解决此问题的正确方法是什么,请建议
【问题讨论】:
-
由于
Router是负责导航的对象,它很自然会持有对ViewControllerA的引用,因为它首先呈现了它。同样,Router将持有对UINagivationController或UITabBarController的引用(如果您的应用程序使用它们) -
@mag-zbc :我完全同意您的说法,但我的困惑是何时/如何将 viewController 引用传递给路由器?在初始化时?作为依赖注入的一部分?然后它会创建一个循环,因为要创建 ViewController 我需要路由器,并且路由器需要对 ViewController 的引用:(
-
你根本没有通过它 -
ViewControllerA应该首先由Router呈现,所以它应该在 @987654347 中创建 @ 和Router应该保留对它的引用。 -
@mag-zbc:对不起,我想我在这里很困惑,假设我有 loginVC,我需要在登录时显示 HomeVC,在这种情况下,LoginVC -> LoginPresenter -> LoginRouter 和登录路由器将创建故事板中的 HomeVC 实例并推送它。在这种情况下,HomeVC 需要创建自己的 HomePresenter 现在问题是如何打破我上面谈到的死锁。请阅读 -> 作为上述声明中的谈话
-
整个应用程序中应该只有一个
Router,这就是VIPER的全部意义——一个负责导航的对象,而不是每个ViewController都有自己的路由器。另外,你说ViewControllers有自己的Presenters,我认为ViewControllers应该是Presenters
标签: ios swift viper-architecture