Viperbase ist eine Implementierung der Viper -Architektur für die Verwendung in der iOS -Plattform.
Dieses Projekt zielt darauf ab, die Viper -Nutzung und -annahme zu vereinfachen und alle erforderlichen Einstellungen für die Arbeit mit dieser Architektur zu erleichtern und zu versuchen, die manuellen Arbeiten aufgrund ihrer Merkmale so weit wie möglich zu reduzieren.
Cocoapods ist ein Abhängigkeitsmanager für Kakaoprojekte. Geben Sie es in Ihrem Podfile an:
pod 'viper-base' , '~> 2.1' Die schlimmste Erfahrung, die Sie bei der Verwendung von Viper haben, besteht darin , alle Dateien, Klassen und Protokolle zu erstellen, die von dieser Architektur benötigt werden. Dies wirkt sich stark auf die Produktivität aus, wodurch eine einfache Aufgabe viel Zeit in Anspruch nimmt.
Mit Xcode können wir personalisierte Vorlagen erstellen. Mit dieser verfügbaren Ressource haben wir beschlossen, eine Vorlage speziell für Viperbase zu erstellen. Mit dieser Vorlage gibt es keine manuelle Arbeit mehr.
Um unsere Vorlage zu installieren und zu verwenden, überprüfen Sie dieses Tutorial.
Ein Modul repräsentiert einen Bildschirm der App.
Diese Implementierung von Viper hat einige Besonderheiten:
Einige Ansätze betrachten die Aufgabe der Modulerstellung als Verantwortung des Routers . Dies verstößt jedoch gegen das Prinzip der einzelnen Verantwortung , da es bereits für die Navigation zwischen Modulen verantwortlich ist.
Um dieses Problem zu lösen, wurde Builder erstellt. Es ist verantwortlich, alle Komponenten des Moduls zu erstellen und die jeweiligen Verbindungen herzustellen.
Auf diese Weise können Entitäten in einem oder mehreren Modulen verwendet werden, da sie einfache Strukturen ohne Geschäftslogik sind.
IOS Architecture, die Navigation wird von einem UiviewController zu einem anderen UiviewController durchgeführt. Aus diesem Grund muss der Router die Reflektion für die Ansicht des aktuellen Moduls nur für Navigationszwecke besitzen und die Ansicht des Zielmoduls von seinem Bauunternehmer erhalten.
Die Verträge definieren, wie die Kommunikation zwischen den Schichten gemacht wird. Ein Modul besteht aus 5 Verträgen:
Die View -Klasse entspricht diesem Protokoll. Es definiert die Kommunikation vom Moderator zu sehen
// MARK: - View Contract
protocol MyModuleViewProtocol : class {
} Die Moderator -Klasse entspricht diesem Protokoll. Es definiert die Kommunikation von Sicht zum Moderator
// MARK: - View Output Contract
protocol MyModuleViewOutputProtocol : class {
} Die Interaktorenklasse entspricht diesem Protokoll. Es definiert die Kommunikation vom Moderator zum Interaktor
// MARK: - Interactor Contract
protocol MyModuleInteractorProtocol : class {
} Die Moderator -Klasse entspricht diesem Protokoll. Es definiert die Kommunikation vom Interaktor zum Moderator
// MARK: - Interactor Output Contract
protocol MyModuleInteractorOutputProtocol : class {
} Die Router -Klasse entspricht diesem Protokoll. Es definiert die Kommunikation vom Moderator zu Router
// MARK: - Router Contract
protocol MyModuleRouterProtocol : class {
} final class MyModuleView : UIViewController , VIPERView {
var presenter : MyModuleViewOutputProtocol !
}
// MARK: - MyModuleViewProtocol
extension MyModuleView : MyModuleViewProtocol {
}Sie müssen nur die im View -Vertrag definierten Methoden implementieren .
final class MyModulePresenter : VIPERPresenter {
weak var view : MyModuleViewProtocol !
var interactor : MyModuleInteractorProtocol !
var router : MyModuleRouterProtocol !
}
// MARK: - MyModuleViewOutputProtocol
extension MyModulePresenter : MyModuleViewOutputProtocol {
}
// MARK: - MyModuleInteractorOutputProtocol
extension MyModulePresenter : MyModuleInteractorOutputProtocol {
}Sie müssen nur die im View Output -Vertrag und des Interactor Output -Vertrags definierten Methoden implementieren .
final class MyModuleInteractor : VIPERInteractor {
weak var presenter : MyModuleInteractorOutputProtocol !
}
// MARK: - MyModuleInteractorProtocol
extension MyModuleInteractor : MyModuleInteractorProtocol {
}Sie müssen nur die im Interaktorenvertrag definierten Methoden implementieren .
final class MyModuleRouter : VIPERRouter {
weak var viewController : UIViewController !
}
// MARK: - MyModuleRouterProtocol
extension MyModuleRouter : MyModuleRouterProtocol {
}Sie müssen nur die im Routervertrag definierten Methoden implementieren .
Im Router kann die Navigation auf zwei Arten erfolgen: das Modul modal präsentieren oder das Modul auf einen Navigationsstapel drücken . Verwenden Sie zur Durchführung der Navigation die folgenden Methoden:
- PresentModule (Withview: Embredin: Animated: Fertigstellung :)
Diese Methode zeigt das nächste Modul modal. Überprüfen Sie die Parameter Details unten:
withView : Ansicht des Moduls zum Navigieren.embedIn : .navigationController oder .none . Der Standardwert ist .noneanimated : Ob die Animation des Übergangs durchführen oder nicht. Der Standardwert ist truecompletion : Handler angerufen, wenn der Übergang beendet ist. Der Standardwert ist nil- PushModule (Withview: Embredin: Animated :)
Diese Methode schiebt das nächste Modul auf den Navigationsstapel . Es funktioniert nur , wenn das aktuelle Modul in einen Navigationscontroller eingebettet ist oder Teil eines Navigationsstapels ist.
withView : Ansicht des Moduls zum Navigieren.embedIn : .navigationController oder .none . Der Standardwert ist .noneanimated : Ob die Animation des Übergangs durchführen oder nicht. Der Standardwert ist true In der Builder -Klasse geben Sie die jeweiligen Klassen für View , Presenter , Interactor und router für das Modul an.
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 {
} Sie definieren auch die Art und Weise, wie die View -Benutzeroberfläche geladen wird , über die Standard -Eigenschaft defaultViewUIType . Es gibt 3 mögliche Werte:
. storyboard ( name : " MyModuleView " , bundle : nil ) . nib ( name : " MyModuleView " , bundle : nil ) . noneDie 4 folgenden Methoden können zum Erstellen eines Moduls verwendet werden. Darüber hinaus können Sie nach den Anforderungen des Moduls benutzerdefinierte Build -Methoden erstellen .
- bauen() :
Erstellt das Modul und gibt eine VIPERModule zurück, die die view und die Referenzen presenter enthält. Sie können die Referenz für die Präsentator verwenden, um Daten zwischen den Modulen zu übergeben .
// MARK: - MyModuleRouterProtocol
extension MyModuleRouter : MyModuleRouterProtocol {
func goToNextModule ( ) {
let module = NextModuleBuilder . build ( )
pushModule ( withView : module . view )
}
}- Build (viewuitype :) :
Diese Methode funktioniert wie die obige Methode, ermöglicht Ihnen jedoch den UI -Typ während des Methodenaufrufs. Diese Methode ist bequem, wenn Sie typealias verwenden, um die Konfiguration des Modulbuilders zu definieren.
typealias MyModuleBuilder = VIPERBuilder < MyModuleView , MyModulePresenter , MyModuleInteractor , MyModuleRouter >
MyModuleBuilder . build ( viewUIType : . storyboard ( name : " MyModuleView " , bundle : nil ) )Sie können diese Methode auch anwenden, wenn Sie Absichtstests rund um die Modulkommunikation durchführen und einen oder mehrere Ebenenklassen gemäß den Testanforderungen verspotten .
import XCTest
class ProjectTests : XCTestCase {
//...
func testModuleCommunication ( ) {
typealias MockModuleBuilder = VIPERBuilder < ModuleMockView , ModuleOriginalPresenter , ModuleOriginalInteractor , ModuleOriginalRouter >
let module = MockModuleBuilder . build ( )
//...
}
} - [veraltet] BuildAtattachtowindow ()
Dies ist eine spezielle Build -Methode, die normalerweise zum Starten des Anfangsmoduls der App verwendet wird, das in AppDelegate -Klasse bezeichnet wird:
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = InitialModuleBuilder.buildAndAttachToWindow()
return true
}
}
[Aktualisiert]: Jetzt müssen Sie zuerst das Modul erstellen , entweder build() oder build(viewUIType:) Methoden und dann aufrufen, dann attachToWindow() oder attachToWindow(withNavigationController:) Neue Methoden:
window = InitialModuleBuilder . build ( ) . attachToWindow ( ) window = InitialModuleBuilder . build ( ) . attachToWindow ( withNavigationController : true )[Wichtig]: Es ist geplant, die veraltete Methode in der nächsten Hauptveröffentlichung zu entfernen (v3.0)
- [veraltet] BuildaTattachTonAvigationController (TabbarItem :)
Diese Methode erstellt das Modul, fügen Sie es an einen Navigationscontroller an und gibt die Navigationscontroller -Referenz zurück . Wenn Sie das Modul in einem Registerkarten -Balkon -Controller verwenden möchten, können Sie tabBarItem -Parameter verwenden, um das Registerkarten -Balkenelement für dieses Modul zu konfigurieren.
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)
]
[Aktualisiert]: Jetzt müssen Sie zuerst das Modul erstellen , entweder build() oder build(viewUIType:) Methoden und dann aufrufen und attachToNavigationController() neue Methode aufrufen:
window = MyModuleBuilder . build ( ) . attachToNavigationController ( )[Wichtig]: Es ist geplant, die veraltete Methode in der nächsten Hauptveröffentlichung zu entfernen (v3.0)
Wenn Sie ein bestimmtes Modul haben, das einige Daten empfangen wird , ist es bequem, eine benutzerdefinierte Build -Methode für dieses Modul zu erstellen. Auf diese Weise ist der Baumeister für die Übergabe dieser Daten an den presenter verantwortlich .
So erstellen Sie benutzerdefinierte Build -Methoden:
build() aufruft.presenter ;view zurück. // 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
}
}Router können diesen Bauunternehmer so nennen:
let view = NextModuleBuilder . build ( someData : " Example of data " , anotherData : " Another example of data " ) pushModule ( withView : view ) presentModule ( withView : view ) Viperbase wird unter der MIT -Lizenz veröffentlicht.