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
!