PS:
这不是一个自以为是的问题。在VIPER中连接各种模块是一个合理的疑问。这是一个理论问题,因此没有附加任何代码。我只需要知道在这种特定情况下如何连接View-Presenter-Router,而不会违反VIPER
我是第一次尝试与VIPER接触。这是我对VIPER的基本了解。
视图:用于显示UI控件并捕获IBActions
并调用其演示者的委托方法来处理事件
演示者::将处理所有与UI相关的数据,并准备进行渲染的数据并将其移交给View。每当需要屏幕转换时,它都会调用其路由器并要求路由器执行转换
PS:演示者中将没有任何UIComponent。因此,主持人中没有import UIKit
声明。
路由器:负责执行屏幕转换,通常是借助线框完成的(可选,但可以在应用中使用此类)
Interactor:。包含所有业务逻辑。只要需要基于业务逻辑进行处理,Presenter就会调用Interactor。
实体:POJO类(简单的Swift对象或Core数据实体)。
现在是一个问题:
如果我的假设正确,那么Presenter应该是普通的Swift类,没有UIKit
访问权限。
如果为true,则假设我按下ViewControllerA
上的一个按钮,并且需要在其上方按下另一个ViewControllerB
,显然ViewControllerA
会与PresenterA
通话并告诉轻按一下按钮,现在PresenterA
就应该与RouterA
对话,并告诉其按下ViewControllerB
。
因为路由器可以访问UIKit
,所以我可以使用情节提要实例或通过xib轻松创建ViewControllerB
的新实例,但是为了推送该实例,我需要ViewControllerA的实例。
但是PresenterA
不能保存对ViewControllerA
的引用,也不能在函数中作为PresenterA
的参数传递,因为UIViewController
属于UIKit
并且Presenters是不应该包含UI语句。
可能的解决方案:
解决方案1:
在创建Router实例时,将相应的ViewController
实例作为其init(依赖项注入阶段)的一部分传递,这样Router便始终可以引用其所属的ViewController
解决方案2:
让Router声明其协议并在ViewController中实现它,只要需要引用ViewController,就使用Router的委托。但这与VIPER的规则矛盾,即路由器不应与View通话。
我在想什么吗?我的假设对吗?如果是,解决此问题的正确方法是什么,请提出
答案 0 :(得分:4)
关于VIPER for iOS应用程序的任何建议或意见值得商,,因为VIPER并不完全适合iOS的UIKit设计。但是如果我要讨论我的两分钱:
首先,我认为UIViewController
非常适合Presenter
在VIPER模式中的角色,因此ViewControllerA
不需要与自身和{之间的任何类进行对话{1}}-只需直接与Router
交流。
第二,应该只有一个Router
对象-因为应用程序只有一个视图/导航堆栈。因此,理想的是为Router
实现Singleton
模式,因此,Router
(或ViewControllerA
,如果您希望让Presenter
扮演角色, ViewControllers
中的View
)不需要保留对Router
的引用。
第三,您不需要将对ViewControllerA
的引用传递给您的Router
-Router
应该已经具有对它的引用,因为应该Router
首先展示它。像这样:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
{
// ...
window?.rootViewController = Router.shared.rootViewController
// ...
}
class Router
{
static let shared = Router()
let rootViewController = ViewControllerA() // or UINavigationController, or UITabBarController etc.
}
Router
应该跟踪导航堆栈并保持对当前显示的ViewController
但这就是我的看法。