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許可發布。