VIPER Design Pattern in Swift für die iOS-Anwendungsentwicklung.

Alles, was einen Anfang hat, hat ein Ende - Autama Buddha. Bildquelle: Screenshot aus dem Film „The Matrix Revolutions“

Design Patterns sind Gottes Geschenk an Softwareentwickler. Hierbei handelt es sich um Techniken, die die Codeduplizierung minimieren, eine hohe Kopplung verhindern und eine übliche Codeschreibweise standardisieren, die eine allgemeine Lösung für wiederkehrende Situationen bei der Entwicklung einer Software bietet. In dieser Geschichte lernen wir ein Entwurfsmuster namens VIPER (View, Interactor, Presenter, Entity und Router.) Für die iOS-Entwicklung kennen.

Voraussetzungen: Bevor Sie mit VIPER beginnen, stellen Sie bitte sicher, dass Sie mit dem architektonischen Entwurfsmuster und dem Delegierungsmuster vertraut sind.

Was ist Viper?

Viper ist ein Entwurfsmuster, das das Paradigma der „Trennung von Interessen“ implementiert. Meist wie MVP oder MVC folgt es einem modularen Ansatz. Eine Funktion, ein Modul. Für jedes Modul hat VIPER fünf (manchmal vier) verschiedene Klassen mit unterschiedlichen Rollen. Keine Klasse geht über ihren alleinigen Zweck hinaus. Diese Klassen folgen.

Ansicht: Klasse, die über den gesamten Code verfügt, mit dem die App-Oberfläche dem Benutzer angezeigt und dessen Antworten abgerufen werden können. Bei Erhalt einer Antwort benachrichtigt View den Presenter.

Moderator: Kern eines Moduls. Es erhält eine Benutzerantwort von der Ansicht und arbeitet dementsprechend. Nur Klasse, um mit allen anderen Komponenten zu kommunizieren. Ruft den Router für Wire-Framing an, Interactor zum Abrufen von Daten (Netzwerkanrufe oder lokale Datenanrufe), Ansicht zum Aktualisieren der Benutzeroberfläche.

Interactor: Hat die Geschäftslogik einer App. Führen Sie hauptsächlich API-Aufrufe aus, um Daten aus einer Quelle abzurufen. Verantwortlich für das Tätigen von Datenanrufen, jedoch nicht unbedingt von sich aus.

Router: Macht das Wire-Framing. Hört vom Moderator zu, welcher Bildschirm präsentiert werden soll, und führt dies aus.

Entität: Enthält einfache Modellklassen, die vom Interaktor verwendet werden.

Unten sehen Sie ein einfaches Diagramm von VIPER

Viper-Architektur

Viper mit Beispiel

Ich habe ein einfaches Projekt erstellt, um Viper zu erklären. Es kann auf GitHub gefunden werden. Es ist eine sehr einfache Anwendung, die eine Nachrichtenüberschrift anzeigt, die von einer externen API abgerufen wird. (wie nutzlos: p).

Viper ist eine delegationsgesteuerte Architektur. Der Großteil der Kommunikation zwischen verschiedenen Ebenen erfolgt also durch Delegation. Eine Schicht ruft eine andere durch ein Protokoll auf. Das Aufrufen der Schicht ruft eine Funktion aus einem Protokoll auf. Die Empfangsebene entspricht diesem Protokoll und implementiert die Funktion.

Im Folgenden werde ich erklären, wie ich VIPER in einem meiner Beispielprojekte implementiert habe. Ich empfehle Ihnen, das Projekt in Github zu öffnen und es durchzulesen, während Sie die Erklärung lesen.

Protokolle

Ich habe eine separate Datei für alle Protokolle erstellt.

Eine Namenskonvention wird befolgt, um ein Protokoll zu benennen. Zum Beispiel "viewToPresenterProtocol". Es ist also ein "Protokoll", das von "dem Moderator" implementiert wird, um zuzuhören, was die "Ansicht" zu sagen hat.

  • PresenterToViewProtocol: Presenter ruft an, View hört zu. Der Präsentator erhält eine Referenz von diesem Protokoll, um auf View zuzugreifen. View entspricht dem Protokoll.
  • ViewToPresenterProtocol: Anrufe anzeigen, Presenter hört zu.
  • InteractorToPresenterProtocol: Interactor ruft an, Presenter hört zu.
  • PresentorToInteractorProtocol: Presenter ruft an, Interactor hört zu.
  • PresenterToRouterProtocol: Presenter ruft an, Router hört zu.

App Flow

View hat eine Referenz von "ViewToPresenterProtocol", um auf den "Presenter" zuzugreifen, und entspricht "PresenterToViewProtocol". In viewDidLoad () wird die Funktion updateView () des Protokolls aufgerufen.

//Aussicht
var presenter: ViewToPresenterProtocol?
Überschreibe func viewDidLoad () {
   super.viewDidLoad ()
   Moderator? .updateView ()
}

Der Presenter hingegen entspricht ViewToPresenterProtocol. Es implementiert also die Funktion updateView ().

//Moderator
var interactor: PresentorToInteractorProtocol ?;
func updateView () {
   Interaktor? .fetchLiveNews ()
}

In updateView () weist Presenter den Interakteur an, einige Live-News-Daten abzurufen.

Interactor entspricht "PresentorToInteractorProtocol". Es implementiert also die Funktion fetchLiveNews (). Diese Funktion versucht, einen Netzwerkanruf zu tätigen und Daten abzurufen. Es enthält eine Referenz von "InteractorToPresenterProtocol", um auf den "Presenter" zuzugreifen.

// Interactor
var presenter: InteractorToPresenterProtocol?

Wenn der Netzwerkaufruf die Daten erfolgreich abgerufen hat, ruft er die folgende Funktion auf.

// Interactor
self.presenter? .liveNewsFetched (news: (arrayObject? [0])!)

wenn nicht

// Interactor
Selbstdarsteller? .liveNewsFetchedFailed ()

Jetzt entspricht der Presenter auch dem InteractorToPresenterProtocol. Es implementiert also diese Funktionen.

//Moderator
func liveNewsFetched (News: LiveNewsModel) {
        anzeigen? .showNews (Nachrichten: Nachrichten);
}
func liveNewsFetchedFailed () {
        view? .showError ()
}

So wird der Ansicht mitgeteilt, ob Nachrichten oder Fehler angezeigt werden sollen.

Jetzt entspricht View „PresenterToViewProtocol“. So implementiert es showNews () und showError (). In diesen beiden Funktionen füllt die Ansicht die Ansicht mit den abgerufenen Daten oder dem Fehler.

Die Entitätsebene

Oben im App-Flow-Abschnitt wird die Entitätsebene nicht behandelt. Es ist nicht direkt mit dem App-Flow verbunden. Aber es ist ein wesentlicher Bestandteil für den Interakteur. Die Objektebene stellt ein Modell bereit, mit dem der Interakteur Objekte aus den abgerufenen Daten erstellt.

Router

Der Router kümmert sich um die Drahtrahmen einer Anwendung. Das Ändern des Bildschirms in einer Anwendung ist eine sehr grundlegende Sache. In VIPER ist die Router-Schicht dafür verantwortlich, dies auszuführen.

Wir haben bereits erwähnt, dass in der VIPER-Architektur jede einzelne Funktionalität ein einzelnes Modul hat und ein Modul diese fünf Schichten enthält. Ein Moderator ruft den Router an, um ein neues Modul zu erstellen. Dann initiiert der Router zuerst die gesamte Layerklasse und sendet das Modul zurück.

In meinem Beispielprojekt ändert sich kein In-App-Modul. Das Routing findet jedoch statt, wenn die App zum ersten Mal gestartet wird. Daher wird in AppDelegates "didFinishLaunchingWithOptions ()" die Funktion createModule () des Routers aufgerufen. Es gibt ein Modul zurück. Die UIWindow-Klasse zeigt dann die Ansicht dieses Moduls an.

Warum und wann man VIPER benutzt

VIPER folgt einer sehr sauberen Architektur. Es isoliert jedes Modul von anderen. Das Ändern oder Beheben von Fehlern ist also sehr einfach, da Sie nur ein bestimmtes Modul aktualisieren müssen. Auch für den modularen Ansatz schafft VIPER eine sehr gute Umgebung für Unit-Tests. Da jedes Modul unabhängig von anderen ist, bleibt die Kopplung sehr gering. Die Arbeitsteilung zwischen den Mitentwicklern ist also ziemlich einfach.

VIPER sollte verwendet werden, wenn die Anforderungen einer Anwendung sehr gut sind. Das Arbeiten mit sich ständig ändernden Anforderungen kann Verwirrung stiften und Codes durcheinander bringen. Daher sollte es nicht in kleinen Projekten verwendet werden, da MVP oder MVC ausreichen. VIPER sollte auch verwendet werden, wenn alle Entwickler des Projekts das Muster vollständig verstehen.

VIPER Werkzeuge

Wenn man VIPER in einem Projekt verwenden möchte, ist es am klügsten, einen automatischen Modulstrukturgenerator zu verwenden. Andernfalls ist das Erstellen von Dateien für Module eintönig. Es sind nur wenige Generatoren online verfügbar.

  • Generamba
  • VIPER-Code
  • VIPER Gen

Fazit

Wie jedes andere Designmuster ist VIPER selbsterklärend. Man muss sich die Hände schmutzig machen, um das ganze Bild zu verstehen. Mein Rat ist, zunächst eine sehr einfache App mit VIPER zu erstellen und dabei die Online-Ressource zu lesen. Mein Github-Repo könnte auch eine gute Referenz sein.

Fröhliches Codieren :)

Es lebe das heilige Bangladesch.

Bangladesch ist eine Welt der Metaphern, des hohen und niedrigen Theaters, der großen Poesie und der Musik. Sie sprechen mit einem Reisbauern und Sie finden einen Dichter. Man lernt einen Straßenfeger kennen und findet einen bemerkenswerten Sänger.
Jean Houston

Referenz :

  1. https://medium.com/ios-os-x-development/ios-architecture-patterns-ecba4c38de52
  2. https://medium.com/@ankoma22/die-gute-das-Bad-und-die-rücksichtslose-Viggers-Architektur-für-ios-Apps-7272001b5347
  3. https://github.com/MindorksOpenSource/iOS-Viper-Architecture/tree/master/iOS-Viper-Architecture
  4. https://sourcemaking.com/design_patterns