[Für Swift-Anfänger] Ich habe versucht, den chaotischen Layoutzyklus von ViewController und View zusammenzufassen

https___qiita-image-store.s3.amazonaws.com_0_45525_670d0038-6f03-095f-ca22-90c510f8babf.png Ich bin Kyoya, Praktikantin bei einer selbst entwickelten Venture-Firma. Da meine Kenntnisse über den Layoutzyklus von ViewController und UIView in mir durcheinander geraten sind, habe ich beschlossen, ihn in mir selbst zu organisieren und mit der Bedeutung der Erklärung für Anfänger zusammenzufassen.

Vorausgesetztes Wissen

Informationen zur Beziehung zwischen ViewController und View

Überraschenderweise denken viele Leute, dass ViewController und View verwirrt sind. Lassen Sie uns sie also einmal hier organisieren.

Dieser Ansichts-Controller, der beim Starten eines Projekts mit Xcode generiert wird, ähnelt Ihnen als Anfänger. Es ist in Ordnung, wenn Sie der Meinung sind, dass dieser Ansichts-Controller die Anzeige der Ansicht auf sehr einfache Weise verwaltet. Eine Ansicht ist einer Ansichtssteuerung zugeordnet. Platzieren Sie beim Erstellen eines Bildschirms Schaltflächen und Beschriftungen in dieser verknüpften UIView. (Wenn sich zwei Ansichten überschneiden, wird die Ansicht in der unteren Hierarchie als übergeordnete Ansicht (Superansicht) und die Ansicht in der oberen Hierarchie als untergeordnete Ansicht (Unteransicht) bezeichnet.)

Über den Lebenszyklus

Ich werde den Lebenszyklus erläutern, der auch Gegenstand dieses Artikels ist. Der Lebenszyklus ist eine Sammlung von Prozessen zum Anzeigen des Bildschirms. Beispielsweise verschiedene Prozesse wie das Einlesen des Ansichtscontrollers in den Speicher, das Berechnen der Positionsinformationen der anzuzeigenden Ansicht und das tatsächliche Anzeigen der Ansicht auf dem Bildschirm. Läuft. Und wie gesagt, es gibt zwei Arten der Verarbeitung im Lebenszyklus: die Verarbeitung auf der Seite des Ansichtscontrollers und die Verarbeitung auf der Seite der Ansicht. Es gibt einen Zeitpunkt für die Anzeige der Ansicht im ViewController, aber es ist in Ordnung zu verstehen, dass die Verarbeitung auf der Ansichtsseite dort erfolgt.

ViewController-Lebenszyklusverarbeitung

Ich werde die Verarbeitung des Lebenszyklus des View Controllers erklären. Abschließend wird der Vorgang wie im Bild unten fortgesetzt. https___qiita-image-store.s3.amazonaws.com_0_45525_670d0038-6f03-095f-ca22-90c510f8babf.png

Wenn Sie sagen, dass Sie zu diesem Artikel gekommen sind, haben Sie wahrscheinlich schon oft solche Bilder gesehen. Und jedes Mal denken manche Menschen, dass sie sich nicht erinnern oder verstehen können. Es ist in Ordnung. Ich werde es auf leicht verständliche Weise erklären.

Zunächst kann der Lebenszyklus des View Controllers grob in die folgenden drei Stufen unterteilt werden. (ViewWillDissappear und viewDidDisappear zum Zeitpunkt des View-Übergangs werden weggelassen.) Laden Sie ViewController → View View, über die ViewController verfügt → Nach Abschluss der Anzeige Schauen wir uns jeden an

Erste Phase: Laden des View Controllers

Registrieren Sie zunächst den Ansichtscontroller, der dem im Speicher anzuzeigenden Bildschirm entspricht (wie ein Datenbereich). Selbst wenn Sie nach der Registrierung einen Bildschirmübergang durchführen, wird dieser nicht aus dem Speicher entfernt, sodass er nur bei der ersten Anzeige aufgerufen wird. Die folgenden zwei Methoden werden hier aufgerufen.

loadView()
viewDidLoad()
viewWillAppear()

loadView () ist der Vorgang des tatsächlichen Registrierens des View-Controllers im Speicher. viewDidLoad () ist ein Prozess, der nach der Registrierung im Speicher aufgerufen wird. LoadView () hat das Laden des View-Controllers beendet, und das Laden der gehaltenen Ansicht ist ebenfalls loadView () ` Da es mit endet, können Sie in viewDidLoad () Eigenschaften für jede Ansicht (Hintergrundfarbeneinstellung, Beschriftungstexteinstellung usw.) wie unten gezeigt festlegen.

    override func viewDidLoad() {
        super.viewDidLoad()
        testView.backgroundColor = .red
    }

viewWillAppear () wird aufgerufen, bevor das Bild angezeigt wird. Dies wird auch beim Wechseln der TabBars aufgerufen, da es jedes Mal aufgerufen wird, wenn der Bildschirm angezeigt wird. Im Gegensatz zu viewDidLoad () wird es dadurch gekennzeichnet, dass es viele Male aufgerufen wird.

Zweite Stufe Ansichtsanzeige

Nachdem Sie in den Speicher gelesen und die Eigenschaften für jede Ansicht festgelegt haben, wird die Ansicht als Nächstes angezeigt. Die folgenden zwei Methoden werden hier aufgerufen.

viewWillLayoutSubViews()
viewDidLayoutSubViews()

viewWillLayoutSubVIews () wird vor dem Start des View-Layouts aufgerufen. Es wird auch aufgerufen, wenn der Bildschirm gedreht wird, wenn die Größe der Ansicht geändert wird oder wenn die Ansicht gelöscht oder hinzugefügt wird. Danach geben wir das Layout der Ansicht ein (später beschrieben). viewDidLayoutSubViews () wird aufgerufen, nachdem das View-Layout fertig ist. Hier ist also das Layout der Ansicht fertig und die Position und Größe der Ansicht werden festgelegt.

Dritte Stufe: Nachdem die Ansicht angezeigt wurde

Die folgende Methode wird hier aufgerufen.

viewDidAppear()

viewDidAppear () wird aufgerufen, nachdem die Bildschirmanzeige beendet ist. Der Prozess, den Sie hier hinzufügen, ist für die Benutzererfahrung grundsätzlich irrelevant. Zum Beispiel das Anzeigen von Protokollen. Da diese Methode mit "viewWillAppear ()" gekoppelt ist, wird sie auch jedes Mal aufgerufen, wenn der Bildschirm angezeigt wird.

Dies ist die Erklärung des Lebenszyklus des View Controllers.

Lebenszyklus anzeigen

Von hier aus fahren wir mit dem View-Lebenszyklus fort. Dieser Prozess wird nach dem vorherigen viewWillLayoutSubViews () aufgerufen. Der View-Lebenszyklus wird durch den folgenden Vorgang angezeigt. Einschränkungsaktualisierung → Aktualisierung der Rahmeninformationen → Rendern (Zeichenprozess) Schauen wir uns jeden an

Erste Phase: Aktualisierung der Einschränkungen

Der Einschränkungsaktualisierungsprozess wird ausgeführt, wenn die Einschränkung geändert wird. Der Prozess, der die Einschränkungsänderung verursacht, ist wie folgt.

Wenn Sie also "NSLayoutConstraints.activate ([~~~])" ausführen, wird updateConstrains () aufgerufen.

Wenn der Einschränkungsaktualisierungsprozess ausgeführt wird, wird das updateConstraints () der Ansicht aufgerufen, das die Einschränkung enthält. Bitte seien Sie hier vorsichtig. Sie könnten denken, dass "updateConstraints ()" mit der View-Controller-Methode gemischt ist, aber da der View-Controller selbst nicht eingeschränkt werden kann, ist diese Methode eine Methode, über die die View verfügt. (Was View hat, bedeutet, dass es auch UIButton und UILabel hat, die von der UIView-Klasse erben).

Aktualisierung der Anrufbeschränkung jederzeit

Es ist auch möglich, den Einschränkungsaktualisierungsprozess jederzeit aufzurufen. Sie können "updateConstraints ()" einer Ansicht aufrufen, für die Einschränkungsaktualisierungen erforderlich sind, indem Sie "updateConstraintsIfNeeded ()" aufrufen. Sie können die Ansicht auch als "Einschränkungsaktualisierung erforderlich" kennzeichnen, indem Sie "setNeedsUpdateCOnstrains ()" aufrufen.

* Achtung * Der Einflussbereich von updateCOnstrainsIfNeeded () ist selbst und seine Unteransicht.

Es ist kompliziert, aber da "updateConstrainsIfNeeded ()" die Verarbeitung von Einschränkungsaktualisierungen auf seine eigene Ansicht und ihre Unteransicht anwendet, selbst wenn Sie "updateConstrainsIfNeeded ()" für eine bestimmte Ansicht ausführen, die der übergeordneten Ansicht Selbst wenn das Einschränkungsaktualisierungsflag in Ansicht gesetzt ist, wird keine Verarbeitung durchgeführt.

Zusammenfassend ist es etwas kompliziert. Wenn Sie "updateConstrainsIfNeeded ()" aufrufen, wird "updateConstrains ()" der Ansicht aufgerufen, die "setNeedsUpdateConstrains ()" in ihrer eigenen Ansicht und ihrer Unteransicht aufgerufen hat. ..

Darüber hinaus können Sie auch die Einschränkung aktualisieren, dass "setNeedsUpdateConstrains ()" zum Zeitpunkt der nächsten Einschränkungsaktualisierung aufgerufen wurde (das Timing bleibt dem System überlassen, dies wird jedoch empfohlen * der Grund wird später beschrieben).

Zweite Stufe: Aktualisierung der Rahmeninformationen

Ich hoffe, Sie können sich Frame-Informationen als Informationen wie Position und Größe der Ansicht vorstellen. Dieser Prozess wird aufgerufen, wenn die Rahmeninformationen aktualisiert werden. Die auszulösenden Auslöser sind wie folgt.

-Ändern Sie den Rahmen der Ansicht -Wenn eine Ansicht hinzugefügt oder gelöscht wird

Die hier aufgerufene Methode ist layoutSubViews (). Diese Methode verwendet die Einschränkungsinformationen, um die Rahmeninformationen zu erstellen. Sie können "layoutSubViews ()" jederzeit aufrufen, genau wie beim Aktualisieren von Einschränkungen. Das Aufrufen von layoutIfNeeded () wird als "Rahmeninformationen müssen aktualisiert werden" gekennzeichnet (kann durch Aufrufen von setNeedsLayoutSubViews ()) von Selbst- und untergeordneten Ansichten gekennzeichnet werden Sie können layoutSubViews () ausführen. Außerdem werden mit "setNeedsLayoutSubViews ()" gekennzeichnete Ansichten zum Zeitpunkt der nächsten Frame-Aktualisierung sofort aktualisiert (das Timing bleibt dem System überlassen, dies wird jedoch empfohlen * der Grund wird später beschrieben). Die Denkweise hier ist eingeschränkt Es ähnelt dem Update von, daher werde ich es nicht im Detail erklären.

LayoutSubViews (), das jederzeit gelesen wird, wird im Hauptthread ausgeführt

Ich habe bereits erwähnt, dass layoutSubViews (), das zum System-Timing ausgeführt wurde, besser ist, aber ich werde erklären, warum. Gleiches gilt für updateConstraints () zum Aktualisieren von Einschränkungen. Bitte beachten Sie, dass die Verarbeitung von "layoutSubViews ()", die von "layoutSubViewsIfNeeded ()" aufgerufen wird, im Hauptthread ausgeführt wird. Anfängern ist es vielleicht nicht vertraut, aber verstehen Sie, dass der Haupt-Thread dem Bereich entspricht, in dem die Verarbeitung stattfindet. In diesem Hauptthread werden auch hier Änderungen an der Benutzeroberfläche vorgenommen. Wenn Sie den Hauptthread mit "layoutSubViewsIfNeeded ()" verwenden, wird das UI-Update daher während dieser Zeit gestoppt, was sich auf die Benutzererfahrung auswirken kann. Im Falle einer Verarbeitung, die mit der Benutzeroberfläche in Zusammenhang zu stehen scheint, rufen wir layoutSubViews () direkt überschreiben auf. LayoutSubVIews (), das zum regulären Zeitpunkt aufgerufen wird, kann ausgeführt werden, ohne den Hauptthread zu belegen, sodass Änderungen an der Benutzeroberfläche nicht betroffen sind.

Vorsichtsmaßnahmen beim Überschreiben

Beim Überschreiben sind zwei Punkte zu beachten. Der erste Punkt ist, dass Sie zuerst "super.layoutSubViews ()" ausführen müssen. Der Frame wird mit super.layoutSubViews () aktualisiert. Wenn Sie dies nicht zuerst tun, müssen Sie Ihre eigene Verarbeitung schreiben, ohne den Frame zu aktualisieren. Dies kann eine Brutstätte für Fehler sein. Der zweite Punkt ist, dass die Rahmeninformationen aus der übergeordneten Ansicht von oben nach unten aktualisiert werden. Da das Update von oben nach unten erfolgt, kann ich das Layout der untergeordneten Ansicht ändern. Wenn ich jedoch eine Änderung an der übergeordneten Ansicht vornehme, wird "layoutSubViews ()" erneut aufgerufen und stürzt ab.

Rendering der dritten Stufe (Zeichnung anzeigen)

Hier wird die Ansicht mithilfe der aktualisierten Rahmeninformationen tatsächlich auf dem Bildschirm gezeichnet. Dieser Vorgang wird zum folgenden Zeitpunkt aufgerufen.

Die hier aufgerufene Methode ist drawRext (_ :). Wenn Sie dies jederzeit aufrufen möchten, können Sie es explizit aufrufen, indem Sie es mit "setNeededDisplay ()" oder "setNeedsDisplayInRect ()" markieren.

Das ist alles für diesen Artikel. Es ist voluminöser geworden, als ich es mir vorgestellt habe, aber bitte beziehen Sie sich darauf. Ich werde einen Artikel schreiben, wenn es neue Entdeckungen gibt.

Vielen Dank.

Recommended Posts

[Für Swift-Anfänger] Ich habe versucht, den chaotischen Layoutzyklus von ViewController und View zusammenzufassen
Ich habe versucht, die Grundlagen von Kotlin und Java zusammenzufassen
Ich habe versucht, die Methoden von Java String und StringBuilder zusammenzufassen
Ich habe versucht, die wichtigsten Punkte des gRPC-Designs und der Entwicklung zusammenzufassen
Ich habe die grundlegende Grammatik von Ruby kurz zusammengefasst
Ich habe versucht, die verwendeten Methoden zusammenzufassen
Ich habe versucht, die Stream-API zusammenzufassen
[Rails] Artikel für Anfänger, um den Fluss von form_with zu organisieren und zu verstehen
Ich habe versucht, die Geschwindigkeit von Graal VM mit JMH zu messen und zu vergleichen
[Für Anfänger] DI ~ Die Grundlagen von DI und DI im Frühjahr ~
05. Ich habe versucht, die Quelle von Spring Boot zu löschen
Ich habe versucht, die Kapazität von Spring Boot zu reduzieren
[Swift] Ich habe bereits viele Informationen, aber ich habe versucht, die Besetzung (as, as !, As?) Auf meine eigene Weise zusammenzufassen.
Ich habe versucht, dies und das von Spring @ Transactional zu überprüfen
Ich habe JAX-RS ausprobiert und mir das Verfahren notiert
[Rails 6.0, Docker] Ich habe versucht, die Konstruktion der Docker-Umgebung und die zum Erstellen eines Portfolios erforderlichen Befehle zusammenzufassen
Ich habe versucht, persönlich nützliche Apps und Entwicklungstools (Entwicklungstools) zusammenzufassen.
Ich habe versucht, eine Umgebung mit WSL2 + Docker + VSCode zu erstellen
Ich habe versucht, persönlich nützliche Apps und Entwicklungstools (Apps) zusammenzufassen.
Ich habe versucht zu erklären, was Sie aus Anfängersicht in einer beliebten Sprache für die Webentwicklung tun können.
Ich habe versucht, mir zu erlauben, die Verzögerung für den Android UDP-Client einzustellen
Ich werde die Verschachtelung von Aussagen erklären, die Anfänger töten
Ich habe versucht, das Problem der "mehrstufigen Auswahl" mit Ruby zu lösen
[Swift5] So erhalten Sie ein Array und eine Reihe von Unterschieden zwischen Arrays
Ich habe versucht, mit Docker eine Plant UML Server-Umgebung zu erstellen
Die Geschichte von Collectors.groupingBy, die ich für die Nachwelt behalten möchte
[Rubiy] Heute Abend habe ich versucht, die Schleifenverarbeitung zusammenzufassen [Zeiten, Pause ...]
Sondervortrag über Multiskalensimulation: Ich habe versucht, den 5. zusammenzufassen
[Tipps] So lösen Sie Probleme mit XCode und Swift für Anfänger
Sondervortrag über Multi-Scale-Simulation: Ich habe versucht, den 8. zusammenzufassen
Ich habe versucht, den Betrieb des gRPC-Servers mit grpcurl zu überprüfen
Sondervortrag über Multi-Scale-Simulation: Ich habe versucht, den 7. zusammenzufassen
Ich habe versucht, das Problem des Google Tech Dev Guide zu lösen
Ich habe versucht, die Unterstützung für iOS 14 zusammenzufassen
Ich habe versucht, das Java-Lernen zusammenzufassen (1)
Ich habe jetzt versucht, Java 8 zusammenzufassen
[Ruby] Ich möchte nur den Wert des Hash und nur den Schlüssel extrahieren
[Einführung in Java] Ich habe versucht, das Wissen zusammenzufassen, das ich für wesentlich halte
Bevor Sie die Funktionen und Punkte der Furima-App vergessen
Ich möchte das Argument der Annotation und das Argument der aufrufenden Methode an den Aspekt übergeben
Ich habe versucht, den CPU-Kern mit Ruby voll auszunutzen
Ich habe versucht, den Zugriff von Lambda → Athena mit AWS X-Ray zu visualisieren
[Ruby] Ich habe versucht, die häufigen Methoden in Paiza zusammenzufassen
[Ruby] Ich habe versucht, die häufigen Methoden mit paiza ② zusammenzufassen
Ich habe versucht, die Grammatik von R und Java zu übersetzen [Von Zeit zu Zeit aktualisiert]
Ich möchte, dass Sie Enum # name () für den Schlüssel von SharedPreference verwenden
(Für Anfänger) Swift UI View Element Collection
Ich habe versucht, Java-Lambda-Ausdrücke zusammenzufassen
Ich habe versucht, das Iterator-Muster zu implementieren