ViperBase是用于在iOS平台中使用的Viper体系结构的实现。
该项目旨在使毒蛇的使用和采用更加容易,从而促进与该体系结构合作的所有必需设置,并试图减少由于其特征而产生的手动工作。
Cocoapods是可可项目的依赖性经理。要将viperbase集成到您的Xcode项目中,请在您的Podfile中指定它:
pod 'viper-base' , '~> 2.1' 使用Viper时,您可能拥有的最糟糕的经验是自己创建此体系结构所需的所有文件,类和协议。这会影响很多生产力,使一项简单的任务需要很多时间。
XCode允许我们创建个性化模板。借助此资源,我们决定为Viperbase创建一个模板。使用此模板,不再有手动工作。
要安装和使用我们的模板,请检查本教程。
一个模块代表应用程序的屏幕。
这种毒蛇的实施具有一些特殊性:
一些方法将模块创建任务视为路由器的责任。但这违反了单一责任原则,因为它已经负责模块之间的导航。
为了解决这个问题,创建了建筑商。它负责创建模块的所有组件并建立各自的连接。
这样,实体可以在一个或多个模块中使用,因为它们是没有业务逻辑的简单结构。
iOS体系结构,导航是从UiviewController到另一个UiviewController执行的。因此,路由器必须为当前模块的视图(仅出于导航目的)而拥有重视,并从其构建器中接收目标模块的视图。
合同定义了如何进行两层之间的通信。一个模块由5个合同组成:
视图类符合此协议。它定义了从主持人到查看的沟通
// MARK: - View Contract
protocol MyModuleViewProtocol : class {
} 演示者类符合此协议。它定义了从视图到主持人的通信
// MARK: - View Output Contract
protocol MyModuleViewOutputProtocol : class {
} 交互式类别符合此协议。它定义了从主持人到互动者的沟通
// MARK: - Interactor Contract
protocol MyModuleInteractorProtocol : class {
} 演示者类符合此协议。它定义了从交互者到主持人的沟通
// MARK: - Interactor Output Contract
protocol MyModuleInteractorOutputProtocol : class {
} 路由器类符合此协议。它定义了从演示者到路由器的通信
// MARK: - Router Contract
protocol MyModuleRouterProtocol : class {
} final class MyModuleView : UIViewController , VIPERView {
var presenter : MyModuleViewOutputProtocol !
}
// MARK: - MyModuleViewProtocol
extension MyModuleView : MyModuleViewProtocol {
}您只需要实现查看合同中定义的方法。
final class MyModulePresenter : VIPERPresenter {
weak var view : MyModuleViewProtocol !
var interactor : MyModuleInteractorProtocol !
var router : MyModuleRouterProtocol !
}
// MARK: - MyModuleViewOutputProtocol
extension MyModulePresenter : MyModuleViewOutputProtocol {
}
// MARK: - MyModuleInteractorOutputProtocol
extension MyModulePresenter : MyModuleInteractorOutputProtocol {
}您只需要实现“视图输出合同”和“交互式输出合同”中定义的方法。
final class MyModuleInteractor : VIPERInteractor {
weak var presenter : MyModuleInteractorOutputProtocol !
}
// MARK: - MyModuleInteractorProtocol
extension MyModuleInteractor : MyModuleInteractorProtocol {
}您只需要实现交互式合同中定义的方法即可。
final class MyModuleRouter : VIPERRouter {
weak var viewController : UIViewController !
}
// MARK: - MyModuleRouterProtocol
extension MyModuleRouter : MyModuleRouterProtocol {
}您只需要实现路由器合同中定义的方法即可。
在路由器中,可以通过两种方式进行导航:将模块呈现或将模块推到导航堆栈上。要执行导航,请使用以下方法:
- presentModule(withView:embedin:andiant:noterion :)
此方法呈现下一个模块。在下面检查参数详细信息:
withView :要导航的模块的视图。embedIn : .navigationController或.none 。默认值是.noneanimated :是否执行过渡的动画。默认值是truecompletion :在过渡完成时打电话给处理程序。默认值是nil- pusphModule(withView:embedin:动画:)
此方法将下一个模块推向导航堆栈。它仅在当前模块嵌入导航控制器中或是导航堆栈的一部分时起作用。
withView :要导航的模块的视图。embedIn : .navigationController或.none 。默认值是.noneanimated :是否执行过渡的动画。默认值是true在Builder类中,您指定各个类别的View , Presenter , Interactor和router层的模块。
final class MyModuleBuilder : VIPERBuilder < MyModuleView , MyModulePresenter , MyModuleInteractor , MyModuleRouter > {
override class var defaultViewUIType : VIPERViewUIType {
return . storyboard ( name : " MyModuleView " , bundle : nil )
}
}
// MARK: - Builder custom methods
extension MyModuleBuilder {
}您还可以通过defaultViewUIType属性来定义视图UI的加载方式。有3个可能的值:
. storyboard ( name : " MyModuleView " , bundle : nil ) . nib ( name : " MyModuleView " , bundle : nil ) . none下面的4种方法可用于构建模块。此外,您可以根据模块需求创建自定义构建方法。
- 建造() :
创建模块并返回包含view和presenter参考的VIPERModule struct。您可以使用演示者参考来传递模块之间的数据。
// MARK: - MyModuleRouterProtocol
extension MyModuleRouter : MyModuleRouterProtocol {
func goToNextModule ( ) {
let module = NextModuleBuilder . build ( )
pushModule ( withView : module . view )
}
}- 构建(viewuitype :) :
此方法与上述方法一样起作用,但它允许您在方法调用期间指定UI类型。当您使用typealias来定义模块构建器的配置时,此方法很方便。
typealias MyModuleBuilder = VIPERBuilder < MyModuleView , MyModulePresenter , MyModuleInteractor , MyModuleRouter >
MyModuleBuilder . build ( viewUIType : . storyboard ( name : " MyModuleView " , bundle : nil ) )如果您意图在模块通信周围进行单元测试,并根据测试需求嘲笑一个或多个层类别,则也可以使用此方法。
import XCTest
class ProjectTests : XCTestCase {
//...
func testModuleCommunication ( ) {
typealias MockModuleBuilder = VIPERBuilder < ModuleMockView , ModuleOriginalPresenter , ModuleOriginalInteractor , ModuleOriginalRouter >
let module = MockModuleBuilder . build ( )
//...
}
} - [弃用] buildandattachtowindow()
这是一种特殊的构建方法,通常用于启动应用程序的初始模块,在AppDelegate类中称为:
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = InitialModuleBuilder.buildAndAttachToWindow()
return true
}
}
[更新]:现在,您必须先使用build() build(viewUIType:)方法构建模块,然后调用attachToWindow()或attachToWindow(withNavigationController:)新方法:
window = InitialModuleBuilder . build ( ) . attachToWindow ( ) window = InitialModuleBuilder . build ( ) . attachToWindow ( withNavigationController : true )[重要]:计划在下一个主要版本(v3.0)中删除弃用方法
- [弃用] buildandattachtonAvigationController(Tabbaritem :)
此方法创建模块,将其连接到导航控制器上,然后返回导航控制器参考。如果您打算在选项卡栏控制器内使用模块,则可以使用tabBarItem参数为该模块配置Tab Bar项目。
let tabBarController = UITabBarController()
let bookmarksItem = UITabBarItem(tabBarSystemItem: .bookmarks, tag: 0)
let contactsItem = UITabBarItem(tabBarSystemItem: .contacts, tag: 1)
let downloadsItem = UITabBarItem(tabBarSystemItem: .downloads, tag: 2)
tabBarController.viewControllers = [
BookmarksBuilder.buildAndAttachToNavigationController(tabBarItem: bookmarksItem),
ContactsBuilder.buildAndAttachToNavigationController(tabBarItem: contactsItem),
DownloadsBuilder.buildAndAttachToNavigationController(tabBarItem: downloadsItem)
]
[更新]:现在,您必须首先构建模块,使用build()或build(viewUIType:)方法,然后调用attachToNavigationController()新方法:
window = MyModuleBuilder . build ( ) . attachToNavigationController ( )[重要]:计划在下一个主要版本(v3.0)中删除弃用方法
如果您有一个特定的模块希望接收一些数据,则很方便为该模块创建自定义构建方法。这样,构建器将负责将此数据传递给presenter 。
创建自定义构建方法:
build()方法的实现;presenter ;view 。 // MARK: - Builder custom methods
extension NextModuleBuilder {
static func build ( someData : Any , anotherData : Any ) -> MyModuleView {
let module = build ( )
module . presenter . someData = someData
module . presenter . anotherData = anotherData
return module . view
}
}路由器可以这样称呼此构建器:
let view = NextModuleBuilder . build ( someData : " Example of data " , anotherData : " Another example of data " ) pushModule ( withView : view ) presentModule ( withView : view ) Viperbase根据MIT许可发布。