Haben Sie einen großen UIViewController? Für viele ja. Einerseits funktioniert es mit Daten, andererseits - mit der Schnittstelle.
Die Aufgaben der Trennung von Logik und Schnittstelle werden in Hunderten von Artikeln zur Architektur beschrieben: MVP, MVVM, VIPER. Sie lösen das Problem des Datenflusses, beantworten jedoch nicht die Frage, wie mit der Benutzeroberfläche gearbeitet werden soll: An einer Stelle verbleiben die Erstellung von Elementen, das Layout, die Konfiguration, die Verarbeitung von Eingaben und die Animation.
Lassen Sie uns die Ansicht vom Controller trennen und sehen, wie loadView () uns hilft.

Die Anwendungsoberfläche für iOS ist die
UIView Hierarchie. Die Aufgaben jeder
view : Elemente erstellen, anpassen, an Orten anordnen, animieren. Dies lässt sich an den Methoden der
UIView: addSubview(), drawRect(), layoutSubviews(). Klasse
UIView: addSubview(), drawRect(), layoutSubviews().Wenn Sie sich die Methoden der
UIViewController Klasse
UIViewController , sehen Sie, dass sie die
view: verwaltet
view: geladen, reagiert auf Ladebildschirme und Benutzeraktionen und zeigt neue Bildschirme an. Oft wird der Code, der in der
UIView soll, in Unterklassen des
UIViewController , dies macht ihn zu groß. Trenne es.
loadView ()
Der Lebenszyklus eines
UIViewController beginnt mit
loadView() . Eine vereinfachte Implementierung sieht folgendermaßen aus:
Wir können die Methode überschreiben und unsere Klasse angeben.
super.loadView() muss nicht aufgerufen werden!
Implementierung von CustomView.swift Der Controller lädt
CustomView, fügt es der Hierarchie hinzu und macht
.frame . Die
.view Eigenschaft ist die Klasse, die wir benötigen:
Der Compiler kennt die Klasse jedoch nicht und glaubt, dass es eine normale
UIView . Beheben wir dies mit einer Typumwandlungsfunktion:
Jetzt können Sie die
CustomView Variablen sehen:
Vereinfachen Sie mit dem zugehörigen TypRuslan Kavetsky schlug vor, die Codeduplizierung mithilfe der Protokollerweiterung zu entfernen:
protocol ViewSpecificController { associatedtype RootView: UIView } extension ViewSpecificController where Self: UIViewController { func view() -> RootView { return self.view as! RootView } }
Für jeden neuen Controller müssen Sie nur das Protokoll und die Unterklasse für seine UIView über typealias :
Code in einer Unterklasse von UIView
Steuerelemente erstellen und konfigurieren
Schriftarten, Farben, Konstanten und Hierarchien können direkt im CustomView-Konstruktor festgelegt werden:
layoutSubviews ()
Der beste Ort für ein manuelles Layout ist die
layoutSubviews() -Methode. Es wird jedes Mal aufgerufen, wenn die
view geändert wird, sodass Sie sich für die korrekten Berechnungen auf die Grenzgröße verlassen können:
Private Kontrollen, öffentliches Eigentum
Wenn noch Zeit ist, mache ich die
property privat, verwalte sie aber über öffentliche Variablen oder Funktionen „im Wissensbereich“. Ein einfacheres Beispiel:
Der Vorteil der Kapselung: Die interne Logik ist hinter der Schnittstelle verborgen. Zum Beispiel kann die Gültigkeit eines Objekts durch die Farbe des Bereichs angezeigt werden, nicht durch das Quadrat, aber der Controller weiß nichts darüber.
Was bleibt in viewDidLoad ()?
Wenn Sie den Interface Builder verwenden, ist
viewDidLoad() häufig leer. Wenn Sie eine
view im Code erstellen, müssen Sie deren Aktionen über das
UIGestureRecognizer binden, einen
UIGestureRecognizer hinzufügen oder Delegaten binden.
Anpassbar über Interface Builder
Die Unterklasse für die
view kann über den Interface Builder (im Folgenden IB) konfiguriert werden.
Sie müssen das
view (nicht den Controller) auswählen und seine Klasse festlegen. Es ist nicht erforderlich, eine eigene
loadView() zu schreiben, der Controller
loadView() dies selbst.
UIView noch
UIView Typ
UIView .

IBOutlet in UIView
Wenn Sie das Steuerelement in der
view auswählen, erkennt der Assistant Editor die
UIView Klasse und bietet sie als zweite Datei im automatischen Modus an. So können Sie
IBOutlet zur
view .

Wenn nicht funktioniertÖffnen Sie die
CustomView Klasse manuell und schreiben Sie
IBOutlet . Jetzt können Sie an der Markierung ziehen und mit der Maus über ein Element in IB fahren.

Wenn Sie eine Schnittstelle im Code erstellen, sind alle Objekte nach
init() zugänglich. Wenn Sie jedoch mit IB arbeiten, wird der Zugriff auf
IBOutlet erst
IBOutlet , nachdem Sie die Schnittstelle von
UIStoryboard in der Methode
awakeFromNib() :
IBAction in UIViewController
Für meinen Geschmack sollte der Controller alle Benutzeraktionen verlassen. Vom Standard:
- Zielaktion von Kontrollen
- Implementierung in
UIViewController - Blockimplementierung
- Reaktion auf
Notification
In diesem Fall steuert der
UIViewController nur die Schnittstelle. Alles, was mit Geschäftslogik zu tun hat, sollte aus dem Controller entfernt werden. Dies ist jedoch eine Auswahl: MVP, VIPER usw.
Ziel-c
In Objective-C können Sie den
UIView Typ vollständig ersetzen. Deklarieren Sie dazu die Eigenschaft mit der gewünschten Klasse, überschreiben Sie
setter und
getter und geben Sie die Klasse an:
Das Ende
Im Beispiel auf GitHub können Sie die Trennung von Klassen für eine einfache Aufgabe betrachten: Die Farbe des Quadrats hängt von seiner Position ab (im grünen Bereich ist es grün, außerhalb ist es rot).
Je komplexer der Bildschirm ist, desto besser ist der Effekt: Der Controller wird reduziert, der Code wird an seinen Platz übertragen. Code wird einfach zum
view portiert, aber die Kapselung erleichtert das Interagieren und Lesen von Code. Manchmal kann die
view mit einem anderen Controller wiederverwendet werden. Beispielsweise reagieren verschiedene Controller für iPhone und iPad auf ihre eigene Weise auf das Erscheinungsbild der Tastatur, dies ändert jedoch nicht den
view .
Ich habe diesen Code in verschiedenen Projekten und mit verschiedenen Leuten verwendet, jedes Mal, wenn das Team die Vereinfachung begrüßte und die Praxis aufnahm. Ich hoffe es gefällt euch auch. Alles einfach
UIViewController !