Warum MVC möglicherweise nicht das beste Muster für Cocoa-Apps ist

MVC steht für Model View Controller, und es ist ein weit verbreitetes architektonisches Muster für die Softwareentwicklung. Es ist das De-facto-Designmuster für die Entwicklung von Kakao, und das schon seit vielen, vielen Jahren. Die meisten von uns können sich Anwendungen nicht ohne sie vorstellen. Sowohl UIKit (iOS) als auch AppKit(macOS) verwenden Sie häufig MVC. Es scheint fast so, als hätten wir keine andere Möglichkeit, Anwendungen für iOS, tvOS, macOS und watchOS zu erstellen.

Selbst wenn Sie mit dem Model-View-Controller-Muster nicht vertraut sind, und wenn Sie Anwendungen für eine Plattform von Apple entwickeln möchten, müssen Sie lernen, wie Ansichten (iOS) und Fenster (macOS) sich auf Controller beziehen und welche Rolle sie spielen Modell spielt in einer typischen Cocoa-Anwendung. Zum Glück ist MVC leicht zu erlernen.

In dieser kurzen Serie erkläre ich, was MVC ist, wie es in einer typischen Cocoa-Anwendung aussieht und warum es nicht die beste Lösung für Cocoa-Entwickler ist.

1. Ein Beispiel

Lassen Sie mich Ihnen zeigen, wie das MVC-Muster in einer typischen Cocoa-Anwendung aussieht. Das Beispiel, das ich Ihnen zeigen werde, konzentriert sich auf iOS, aber alles, was wir besprechen, gilt auch für tvOS, macOS und watchOS. Öffnen Sie Xcode und erstellen Sie einen neuen iOS Projekt basierend auf dem Einzelansicht-Anwendung Vorlage.

Nennen Sie das Projekt MVC, und setzen Sprache zu Schnell und Geräte zu iPhone. Ich verwende Xcode 8 für dieses Tutorial. Die Konfigurationsoptionen des Projekts sehen möglicherweise etwas anders aus, wenn Sie Xcode 9 verwenden.

Wie der Name schon sagt, definiert das Model-View-Controller-Muster drei Komponenten, die Modell-, das Aussicht, und das Regler. Ich zeige Ihnen, wo Sie diese Komponenten in einem typischen iOS-Projekt finden können.

Controller

Die Controller einer iOS-Anwendung sind View-Controller, Instanzen der UIViewController Klasse oder eine Unterklasse davon. Das UIViewController Klasse ist in der definiert UIKit Rahmen. Weil wir uns für das entschieden haben Einzelansicht-Anwendung Als wir beim Einrichten des Projekts eine Vorlage erstellt haben, hat Xcode einen Controller erstellt, mit dem wir beginnen können ViewController Klasse, definiert in ViewController.Swift. Es erbt von der UIViewController Klasse.

Wie der Name schon sagt, a UIViewController Instanz ist für die Kontrolle einer Sicht, einer Instanz der UIView Klasse. Jeder Ansichts-Controller in einem iOS-Projekt enthält einen starken Bezug zu einer Ansicht, einer anderen Komponente des Model-View-Controller-Musters. Das UIView Klasse ist auch in der definiert UIKit Rahmen.

Ansichten

Wir finden die Ansichtskomponente im Haupt-Storyboard des Projekts. Öffnen Hauptplatine in dem Projektnavigator auf der linken Seite und überprüfen Sie die Controller-Szene anzeigen. Die Szene enthält einen View Controller, eine Instanz des ViewController Klasse, und es verwaltet ein UIView Beispiel.

Wählen Aussicht im Storyboard auf der linken Seite und öffnen Sie die Identitätsinspektor zur Rechten. Das Klasse Feld der Ansicht ist auf gesetzt UIView. In einer iOS-Anwendung handelt es sich bei Ansichten normalerweise um Instanzen von UIKit's UIView Klasse oder eine Unterklasse davon.

Modelle

Bisher haben wir die Controller-Ebene und die Ansichtsebene untersucht. Aber wo finden wir die Modellebene des Projekts? Das Modell ist fast immer spezifisch für das Projekt, an dem Sie arbeiten, und es liegt an Ihnen, das Modell des Projekts zu definieren, zu implementieren und zu verwenden. Ich schreibe Modell-, In der Regel haben Sie jedoch mehrere Modelle, abhängig von der Komplexität Ihres Projekts.

Fügen Sie das letzte Stück des MVC-Puzzles hinzu, indem Sie ein Modell erstellen. Erstellen Sie eine neue Swift-Datei und benennen Sie sie Personenwechsel.

Wählen Personenwechsel in dem Projektnavigator auf der linken Seite und definieren Sie eine Struktur mit dem Namen Person. Wir definieren drei Eigenschaften: 

  • Vorname vom Typ String
  • Nachname vom Typ String
  • Alter vom Typ Int
struct Person let firstName: String let Nachname: String Alter lassen: Int

Sie haben jetzt ein Modell, das Sie in Ihrem Projekt verwenden können. Lassen Sie uns einfach bleiben und eine Eigenschaft definieren, Person, vom Typ Person? in dem ViewController Klasse. Wir schaffen ein Person Instanz in der View-Controller viewDidLoad () Methode und ordnen Sie es dem zu Person Eigentum.

UIKit-Klasse importieren ViewController: UIViewController // MARK: - Eigenschaften var person: Person? // MARK: - View Life Cycle überschreiben func viewDidLoad () super.viewDidLoad () // Person erstellen Person = Person (Vorname: "John", Nachname: "Doe", Alter: 40)

Was wir in diesem Beispiel sehen, ist in Cocoa-Anwendungen, die mit dem Model-View-Controller-Muster betrieben werden, sehr verbreitet. Der Ansichtscontroller besitzt und verwaltet das Modell und verwendet das Modell, um seine Ansicht aufzufüllen. In einer komplexeren Anwendung laden Sie die Modelldaten aus einem permanenten Speicher oder holen sie von einem Remote-Back-End ab.

Definieren wir einen Auslass für eine UILabel Instanz im View-Controller und fügen Sie im Haupt-Storyboard dem Controller-Szene anzeigen.

UIKit-Klasse importieren ViewController: UIViewController // MARK: - Eigenschaften @IBOutlet var label: UILabel!…

In der Ansicht Controller viewDidLoad () Methode, wir packen sicher den Wert aus, der in gespeichert ist Person Eigenschaft und verwenden Sie ihre Daten, um die Text Eigentum der UILabel Beispiel.

func viewDidLoad () überschreiben super.viewDidLoad () // Person erstellen = Person (Vorname: "John", Nachname: "Doe", Alter: 40) \ (person.lastName), \ (person.firstName) (\ (person.age)) "

Das Ergebnis ist nicht sehr überraschend, wenn Sie mit der Entwicklung von Kakao vertraut sind. Das ist es, was wir enden.

2. Was ist Model-View-Controller??

Das Model-View-Controller-Pattern ist leicht zu verstehen und aufzugreifen. Trotz seiner Einfachheit finden Sie eine Vielzahl von Geschmacksrichtungen des MVC-Musters. MVC bietet nur einen Basisentwurf an, der an die Plattform angepasst werden kann, auf der er verwendet wird. 

Das Model-View-Controller-Pattern, das Sie unter iOS, tvOS, macOS und watchOS kennen, unterscheidet sich in subtiler Weise von der ursprünglichen Definition. Die Unterschiede zur ursprünglichen Definition sind zwar geringfügig, haben jedoch einen erheblichen Einfluss auf den von Ihnen geschriebenen Code sowie auf die Wartbarkeit des Projekts.

Smalltalk

Das Model-View-Controller-Muster ist ein altes Designmuster. In den 70er Jahren wurde es erstmals in Smalltalk vorgestellt. Das Muster wurde von Trygve Reenskaug konzipiert. Im Laufe der Jahre hat sich das Model-View-Controller-Muster in vielen Sprachen und Frameworks wie Java, Rails und Django etabliert.

Ich habe bereits erwähnt, dass das MVC-Muster Anwendungen in drei verschiedene Komponenten aufteilt: Modell-, Aussicht, und Regler. Die ursprüngliche Implementierung des Musters definiert, dass die Ansicht für die Anzeige der Modelldaten für den Benutzer verantwortlich ist. Der Benutzer interagiert mit der Anwendung über die Ansichtsebene. Der Controller ist für die Handhabung der Benutzerinteraktion und die Bearbeitung der Modelldaten verantwortlich. Die Ansicht visualisiert diese Änderungen für den Benutzer. Wie im untenstehenden Diagramm dargestellt, spielt das Modell, wie es von Reenskaug entworfen wurde, eine Schlüsselrolle im MVC-Muster.

MVC und Kakao

Die Implementierung, die wir in der Entwicklung von Kakao verwenden, unterscheidet sich von Reenskaugs ursprünglichem Design. Sehen Sie sich das folgende Diagramm an, um die Unterschiede dieser Unterschiede besser zu verstehen.

Wie ich bereits erwähnt habe, haben Sicht und Controller eine enge Beziehung. In einer typischen iOS-Anwendung enthält ein Controller einen starken Bezug zu der von ihm verwalteten Ansicht. Die Ansicht ist ein dummes Objekt, das weiß, wie Daten angezeigt werden und auf Benutzerinteraktion reagieren. Das Ergebnis ist eine sehr wiederverwendbare Komponente.

Der Controller spielt eine wichtige Rolle in Cocoa-Anwendungen, die mit dem Model-View-Controller-Muster betrieben werden. Es übernimmt einige Aufgaben des Modells in der ursprünglichen MVC-Implementierung von Reenskaug. Ansicht und Modell kommunizieren nicht direkt miteinander. Stattdessen gehört das Modell normalerweise dem Controller, mit dem es die von ihm verwaltete Ansicht konfiguriert und auffüllt.

Ich hoffe, Sie können die subtilen Unterschiede zwischen der ursprünglichen Implementierung von Reenskaug in Smalltalk und der gewohnten Cocoa-Implementierung erkennen. Die Unterschiede sind geringfügig, aber wie ich gleich besprechen werde, ist der Einfluss, den sie haben, wichtig.

3. Das Gute: Trennung von Bedenken und Wiederverwendbarkeit

Bevor wir uns die Probleme ansehen, die MVC einführt, möchte ich Ihnen zeigen, warum das Model-View-Controller-Muster in der Softwareentwicklung ein so beliebtes und weit verbreitetes Muster ist. Das Model-View-Controller-Muster, das wir in der Cocoa-Entwicklung verwenden, hat eine Reihe klarer Vorteile, die es von Reenskaugs ursprünglicher Implementierung übernommen hat.

Der offensichtlichste Vorteil des Model-View-Controller-Musters ist a Trennung von Bedenken. Die Ansichtsschicht ist beispielsweise dafür verantwortlich, dem Benutzer Daten zu präsentieren. Die Modell- und Controller-Layer befassen sich nicht mit der Darstellung von Daten. Wenn Sie jedoch MVC in einem Cocoa-Projekt verwendet haben, wissen Sie, dass dies nicht immer der Fall ist. Ich werde gleich mehr darüber sprechen.

Ein direkter Vorteil dieser Trennung von Bedenken ist Wiederverwendbarkeit. Jede der Komponenten des Model-View-Controller-Musters ist auf eine bestimmte Aufgabe fokussiert. Dies bedeutet, dass die Bausteine ​​einer MVC-Anwendung oft einfach wiederverwendet werden können. Es ermöglicht auch, dass diese Komponenten lose gekoppelt sind, was ihre Wiederverwendbarkeit erhöht. Dies gilt jedoch nicht für jede Komponente. In einem Cocoa-Projekt zum Beispiel sind Controller häufig anwendungsspezifisch und nicht für die Wiederverwendung geeignet.

Die Ansichten und Modelle eines Projekts sind jedoch bei entsprechender Planung in hohem Maße wiederverwendbar. Tabellen- und Sammlungsansichten sind beispielsweise UIView Unterklassen, die in Millionen von Anwendungen verwendet werden. Da eine Tabellensicht die Benutzerinteraktion an ein anderes Objekt delegiert und eine Datenquelle nach den anzuzeigenden Daten fragt, kann sie sich ausschließlich auf die Datenpräsentation und die Benutzerinteraktion konzentrieren.

4. Das Schlechte: Massive View Controller

Die meisten Entwickler verstehen schnell, was das Model-View-Controller-Pattern für die Tabelle bedeutet und wie es implementiert werden sollte. Leider hat das Model-View-Controller-Muster auch eine unschöne Seite. Ich habe bereits über Wiederverwendbarkeit und Trennung von Bedenken geschrieben. Ich bin mir sicher, dass ich Sie nicht von diesen Vorteilen überzeugen muss. Eine Tabellenansicht ist sehr wiederverwendbar und unglaublich performant. Entwickler können UIKit-Standardkomponenten in ihren Anwendungen verwenden, ohne dass Unterklassen oder Anpassungen erforderlich sind.

Die Grenzen von MVC erreichen

Aber das ist nur ein Teil der Geschichte. Sie wissen, wann Sie an die Grenzen von MVC stoßen, wenn sich massive View-Controller in Ihr Projekt eingeschlichen haben. Es ist Zeit für Änderungen, wenn Sie Hunderte oder Tausende von Codezeilen durchforsten, um die gewünschte Methode zu finden. 

Dumping in den Controller

Die meisten Entwickler wissen, was in die Ansichts- und Modellschichten einer typischen Cocoa-Anwendung mit dem Model-View-Controller-Muster fließt. Welche Komponente ist jedoch für die Formatierung der Daten verantwortlich, die dem Benutzer angezeigt werden? Denken Sie daran, dass Ansichten dumm und wiederverwendbar sein sollen. Die Ansicht sollte keine Daten formatieren müssen. Recht? Es sollte nur wissen, wie man Daten präsentiert und auf Benutzerinteraktion reagiert. Sollte sich das Modell mit der Datenformatierung befassen??

Und was ist mit Networking? Das ist sicherlich nicht die Aufgabe der Sicht. Sollte es an das Modell delegiert werden? Das hört sich nicht richtig an. Warum gleiten wir diesen Code nicht in den Controller? Es fühlt sich nicht richtig an, aber für den Moment reicht es.

Nach vielen Codezeilen erhalten Sie einen Controller, der zum Platzen bereit ist, und einen Albtraum zum Testen. Testen? Ich höre dich. Ich möchte keinen View-Controller testen, der darunter leidet Massive-View-Controller-Syndrom entweder.

5. Eine bessere Lösung

Sie haben mit guten Absichten begonnen, aber am Ende haben Sie ein Projekt mit einer Sammlung übergewichtiger Controller erhalten, die schwer zu verwalten und zu warten sind. Sie freuen sich nicht darauf, dem Projekt, an dem Sie gerade arbeiten, neue Funktionen hinzuzufügen, da das Öffnen dieser Ansichtscontroller krank macht. Klingt das bekannt??

Es ist wichtig zu wissen, dass dies ein allgemeines Szenario ist. Viele Entwickler stoßen an die Grenzen des Model-View-Controller-Patterns und erkennen, dass sie etwas Besseres benötigen. Die Chancen stehen gut, dass Sie bereits mehrere Alternativen geprüft haben, wie z MVP (Model-View-Presenter) oder MVVM (Model-View-ViewModel).

In der nächsten Folge dieser Serie werde ich die Ansicht vergrößern Model-View-ViewModel Muster. Wenn Sie bereits mit dem Model-View-Controller-Muster gearbeitet haben, wird Ihnen das seltsam vorkommen. Das Model-View-ViewModel-Muster bringt jedoch einige Verbesserungen an der Tabelle, die für die Cocoa-Entwicklung sehr gut funktionieren.

Und während Sie warten, lesen Sie einige unserer anderen Beiträge zur Entwicklung von Cocoa-Apps!