Understanding the iOS 13 Scene Delegate

Published by donnywals on October 28, 2019October 28, 2019

Wenn Sie ein neues Projekt in Xcode 11 erstellen, werden Sie vielleicht etwas bemerken, das Sie bisher nicht gesehen haben. Anstatt nur eine AppDelegate.swift-Datei, eine ViewController.swift, ein Storyboard und einige andere Dateien zu erstellen, erstellt Xcode jetzt eine neue Datei für Sie: die SceneDelegate.swift-Datei. Wenn du diese Datei noch nie gesehen hast, kann es ziemlich verwirrend sein zu verstehen, was sie ist und wie du diesen neuen Szenendelegaten in deiner App verwenden sollst.

Am Ende dieses Blogbeitrags wirst du wissen:

  • Wofür der Szenendelegat verwendet wird.
  • Wie du deinen Szenendelegaten effektiv implementieren kannst.
  • Warum der Szenendelegierte ein wichtiger Bestandteil von iOS 13 ist.

Lassen Sie uns gleich loslegen, ja?

Untersuchen Sie die neue Xcode-Projektvorlage

Wenn Sie ein neues Xcode-Projekt erstellen, haben Sie die Möglichkeit zu wählen, ob Sie SwiftUI oder Storyboards verwenden möchten. Unabhängig davon, wie Sie sich entscheiden, generiert Xcode eine neue Art von Projektvorlage, auf der Sie aufbauen können. Wir werden uns die SceneDelegate.swift– und AppDelegate.swift-Dateien im nächsten Abschnitt genauer ansehen. Wichtig ist jetzt nur, dass Sie verstehen, dass Xcode diese Dateien für Sie erstellt hat.

Zusätzlich zu diesen beiden Delegatendateien tut Xcode noch etwas anderes, das etwas subtiler ist. Schauen Sie sich Ihre Info.plist-Datei genau an. Sie sollten einen neuen Schlüssel namens Application Scene Manifest mit einem Inhalt ähnlich dem folgenden Bild sehen:

Screenshot des Szenenmanifests der Datei Info.plist

Screenshot des Szenenmanifests der Datei Info.plist

Dieses Szenenmanifest gibt einen Namen und eine Delegatenklasse für Ihre Szene an. Beachten Sie, dass diese Eigenschaften zu einem Array (Application Session Role) gehören, was bedeutet, dass Sie mehrere Konfigurationen in Ihrem Info.plist haben können. Ein sehr viel wichtigerer Schlüssel, den Sie vielleicht schon im obigen Screenshot gesehen haben, ist Enable Multiple Windows. Diese Eigenschaft ist standardmäßig auf NO eingestellt. Wenn Sie diese Eigenschaft auf YES setzen, können Benutzer mehrere Fenster Ihrer Anwendung auf iPadOS (oder sogar auf macOS) öffnen. Die Möglichkeit, mehrere Fenster einer iOS-Anwendung nebeneinander auszuführen, ist ein großer Unterschied zu der Ein-Fenster-Umgebung, mit der wir bisher gearbeitet haben, und die Möglichkeit, mehrere Fenster zu haben, ist der gesamte Grund dafür, dass der Lebenszyklus unserer App jetzt an zwei Stellen statt an einer gepflegt wird.

Lassen Sie uns einen genaueren Blick auf AppDelegate und SceneDelegate werfen, um besser zu verstehen, wie diese beiden Delegaten zusammenarbeiten, um die Unterstützung für mehrere Fenster zu ermöglichen.

Verstehen Sie die Rollen von AppDelegate und SceneDelegate

Wenn Sie Apps vor iOS 13 entwickelt haben, kennen Sie wahrscheinlich Ihr AppDelegate als den einen Ort, der so ziemlich alles tut, was mit dem Start, dem Vordergrund und dem Hintergrund Ihrer Anwendung zu tun hat. In iOS 13 hat Apple einige der AppDelegate-Verantwortlichkeiten in den SceneDelegate verschoben. Werfen wir einen kurzen Blick auf jede dieser beiden Dateien.

Verantwortlichkeiten von AppDelegate

Die AppDelegate ist auch in iOS 13 der Haupteinstiegspunkt für eine Anwendung. Apple ruft AppDelegate-Methoden für verschiedene Lebenszyklusereignisse auf Anwendungsebene auf. In Apples Standardvorlage finden Sie drei Methoden, deren Verwendung Apple für wichtig hält:

  • func application(_:didFinishLaunchingWithOptions:) -> Bool
  • func application(_:configurationForConnecting:options:) -> UISceneConfiguration
  • func application(_:didDiscardSceneSessions:)

Diese Methoden sind mit einigen Kommentaren versehen, die ihre Funktion ausreichend detailliert beschreiben, um sie zu verstehen. Aber lassen Sie uns sie trotzdem schnell durchgehen.

Wenn Ihre Anwendung gerade gestartet wird, wird func application(_:didFinishLaunchingWithOptions:) -> Bool aufgerufen. Diese Methode wird verwendet, um die Anwendung einzurichten. In iOS 12 oder früher hast du diese Methode vielleicht verwendet, um ein UIWindow-Objekt zu erstellen und zu konfigurieren und dem Fenster eine UIViewController-Instanz zuzuweisen, damit es angezeigt wird.

Wenn deine App Szenen verwendet, ist dein AppDelegate nicht mehr dafür verantwortlich, dies zu tun. Da Ihre Anwendung jetzt mehrere Fenster oder UISceneSessions aktiv haben kann, macht es nicht viel Sinn, ein Einzelfenster-Objekt in der AppDelegate zu verwalten.

Die func application(_:configurationForConnecting:options:) -> UISceneConfiguration wird immer dann aufgerufen, wenn Ihre Anwendung eine neue Szene oder ein Fenster für iOS zur Anzeige bereitstellen soll. Beachten Sie, dass diese Methode nicht beim ersten Start Ihrer Anwendung aufgerufen wird, sondern nur, um neue Szenen zu erhalten und zu erstellen. Wir werden das Erstellen und Verwalten mehrerer Szenen in einem späteren Blogbeitrag genauer betrachten.

Die letzte Methode in der AppDelegate-Vorlage ist func application(_:didDiscardSceneSessions:). Diese Methode wird immer dann aufgerufen, wenn ein Benutzer eine Szene verwirft, z. B. indem er sie im Multitasking-Fenster wegwischt oder wenn Sie dies programmatisch tun. Wenn Ihre App nicht läuft, wenn der Benutzer dies tut, wird diese Methode für jede verworfene Szene kurz nach dem Aufruf von func application(_:didFinishLaunchingWithOptions:) -> Bool aufgerufen.

Zusätzlich zu diesen Standardmethoden kann Ihre AppDelegate noch verwendet werden, um URLs zu öffnen, Speicherwarnungen abzufangen, zu erkennen, wann Ihre App beendet wird, ob sich die Uhr des Geräts signifikant geändert hat, zu erkennen, wann ein Benutzer sich für Fernbenachrichtigungen registriert hat und mehr.

Tipp:
Wenn Sie derzeit AppDelegate verwenden, um das Erscheinungsbild der Statusleiste Ihrer App zu verwalten, müssen Sie in iOS 13 möglicherweise einige Änderungen vornehmen. Mehrere Methoden, die sich auf die Statusleiste beziehen, sind in iOS 13 veraltet.

Nachdem wir nun ein besseres Bild von den neuen Aufgaben der AppDelegate haben, werfen wir einen Blick auf die neue SceneDelegate.

Verantwortlichkeiten des SceneDelegate

Wenn man den AppDelegate als das Objekt betrachtet, das für den Lebenszyklus der Anwendung verantwortlich ist, ist der SceneDelegate für das verantwortlich, was auf dem Bildschirm angezeigt wird: die Szenen oder Fenster. Bevor wir weitermachen, sollten wir einige szenenbezogene Begriffe einführen, denn nicht jeder Begriff bedeutet das, was man sich darunter vorstellt.

Wenn man es mit Szenen zu tun hat, ist das, was für den Benutzer wie ein Fenster aussieht, eigentlich ein UIScene, das von einem UISceneSession verwaltet wird. Wenn wir also von Fenstern sprechen, beziehen wir uns in Wirklichkeit auf UISceneSession-Objekte. Ich werde versuchen, mich im Laufe dieses Blogbeitrags so weit wie möglich an diese Terminologie zu halten.

Da wir nun auf der gleichen Seite sind, lassen Sie uns einen Blick auf die SceneDelegate.swift-Datei werfen, die Xcode beim Erstellen unseres Projekts erstellt hat.

Die SceneDelegate.swift-Datei enthält standardmäßig mehrere Methoden:

  • scene(_:willConnectTo:options:)
  • sceneDidDisconnect(_:)
  • sceneDidBecomeActive(_:)
  • sceneWillResignActive(_:)
  • sceneWillEnterForeground(_:)
  • sceneDidEnterBackground(_:)

Diese Methoden sollten Ihnen sehr vertraut vorkommen, wenn Sie mit dem AppDelegate vertraut sind, das vor iOS 13 existierte. Schauen wir uns zuerst scene(_:willConnectTo:options:) an, diese Methode kommt Ihnen wahrscheinlich am wenigsten bekannt vor und ist die erste Methode, die im Lebenszyklus eines UISceneSession aufgerufen wird.

Die Standardimplementierung von scene(_:willConnectTo:options:) erstellt Ihre anfängliche Inhaltsansicht (ContentView, wenn Sie SwiftUI verwenden), erstellt ein neues UIWindow, setzt die rootViewController des Fensters und macht dieses Fenster zum Hauptfenster. Man könnte meinen, dass dieses Fenster das Fenster ist, das der Benutzer sieht. Das ist aber leider nicht der Fall. Fenster gab es schon vor iOS 13 und sie stellen das Ansichtsfenster dar, in dem Ihre App arbeitet. Das UISceneSession steuert also das sichtbare Fenster, das der Benutzer sieht, das UIWindow, das du erstellst, ist die Container-Ansicht für deine Anwendung.

Neben dem Einrichten von Anfangsansichten kannst du scene(_:willConnectTo:options:) verwenden, um deine Szenen-UI wiederherzustellen, falls deine Szene in der Vergangenheit getrennt wurde. Zum Beispiel, weil sie in den Hintergrund gesendet wurde. Sie können auch das connectionOptions-Objekt auslesen, um zu sehen, ob Ihre Szene aufgrund einer HandOff-Anforderung erstellt wurde oder vielleicht, um eine URL zu öffnen. Ich werde Ihnen später in diesem Blogbeitrag zeigen, wie das geht.

Wenn Ihre Szene eine Verbindung hergestellt hat, ist die nächste Methode im Lebenszyklus Ihrer Szene sceneWillEnterForeground(_:). Diese Methode wird aufgerufen, wenn Ihre Szene die Bühne betritt. Dies kann der Fall sein, wenn Ihre Anwendung vom Hintergrund in den Vordergrund wechselt, oder wenn sie gerade zum ersten Mal aktiv wird. Als nächstes wird sceneDidBecomeActive(_:) aufgerufen. Dies ist der Punkt, an dem Ihre Szene eingerichtet, sichtbar und bereit für die Verwendung ist.

Wenn Ihre Anwendung in den Hintergrund geht, werden sceneWillResignActive(_:) und sceneDidEnterBackground(_:) aufgerufen. Ich werde jetzt nicht auf diese Methoden eingehen, da ihr Zweck für jede Anwendung unterschiedlich ist, und die Kommentare in der Xcode-Vorlage erklären ziemlich gut, wann diese Methoden aufgerufen werden. Ich bin sicher, dass Sie selbst herausfinden können, wann diese Methoden aufgerufen werden.

Eine interessantere Methode ist sceneDidDisconnect(_:). Immer wenn Ihre Szene in den Hintergrund geschickt wird, kann iOS beschließen, die Verbindung zu trennen und Ihre Szene zu löschen, um Ressourcen freizugeben. Das bedeutet nicht, dass Ihre App beendet wurde oder nicht mehr läuft, es bedeutet einfach, dass die Szene, die an diese Methode übergeben wurde, nicht mehr aktiv ist und von ihrer Sitzung getrennt wird.

Bitte beachten Sie, dass die Sitzung selbst nicht notwendigerweise auch verworfen wird, iOS kann sich jederzeit entscheiden, eine Szene wieder mit einer Szenensitzung zu verbinden, zum Beispiel, wenn ein Benutzer eine bestimmte Szene wieder in den Vordergrund bringt.

Das Wichtigste, was in sceneDidDisconnect(_:) zu tun ist, ist, alle Ressourcen zu verwerfen, die Sie nicht benötigen. Dabei kann es sich um Daten handeln, die leicht von der Festplatte oder aus dem Netzwerk geladen werden können, oder um andere Daten, die Sie leicht wiederherstellen können. Es ist auch wichtig, dass Sie alle Daten behalten, die nicht einfach wiederhergestellt werden können, wie z.B. alle Eingaben, die der Benutzer in einer Szene gemacht hat und von denen er erwartet, dass sie noch da sind, wenn er zu einer Szene zurückkehrt.

Betrachten Sie eine Textverarbeitungsanwendung, die mehrere Szenen unterstützt. Wenn ein Benutzer in einer Szene arbeitet und diese dann verlässt, um in Safari zu recherchieren und seine Musik in Spotify zu ändern, würde er auf jeden Fall erwarten, dass all seine Arbeit in der Textverarbeitungs-App noch vorhanden ist, auch wenn iOS die Szene der Textverarbeitungs-App für eine Weile unterbrochen haben könnte. Um dies zu erreichen, muss die App die erforderlichen Daten aufbewahren, und sie sollte den aktuellen App-Status in einem NSUserActivity-Objekt kodieren, das später in scene(_:willConnectTo:options:) gelesen werden kann, wenn die Szene wieder verbunden wird.

Da dieser Arbeitsablauf des Verbindens, Trennens und Wiederverbindens von Szenen die guten Apps von den großartigen unterscheiden wird, lassen Sie uns einen Blick darauf werfen, wie Sie die Wiederherstellung des Zustands in Ihrer App implementieren können.

Das Ausführen zusätzlicher Szeneneinstellungen

Es gibt mehrere Gründe, warum Sie zusätzliche Einstellungen vornehmen müssen, wenn eine Szene eingerichtet wird. Sie müssen vielleicht eine URL öffnen, eine Übergabeanforderung bearbeiten oder den Zustand wiederherstellen. In diesem Abschnitt konzentriere ich mich hauptsächlich auf die Wiederherstellung des Zustands, da dies möglicherweise das komplexeste Szenario ist, mit dem Sie umgehen müssen.

Die Wiederherstellung des Zustands beginnt, wenn Ihre Szene getrennt wird und sceneDidDisconnect(_:) aufgerufen wird. Zu diesem Zeitpunkt ist es wichtig, dass Ihre Anwendung bereits einen Zustand eingerichtet hat, der später wiederhergestellt werden kann. Dies geschieht am besten durch die Verwendung von NSUserActivity in Ihrer Anwendung. Wenn Sie NSUserActivity verwenden, um Handoff, Siri Shortcuts, Spotlight-Indizierung und mehr zu unterstützen, haben Sie nicht viel zusätzliche Arbeit zu tun. Wenn Sie NSUserActivity noch nicht verwenden, machen Sie sich keine Sorgen. Eine einfache Benutzeraktivität könnte etwa so aussehen:

let activity = NSUserActivity(activityType: "com.donnywals.DocumentEdit")activity.userInfo = 

Bitte beachten Sie, dass diese Benutzeraktivität nicht so strukturiert ist, wie Apple es empfiehlt, sondern ein sehr einfaches Beispiel ist, das die Wiederherstellung des Status veranschaulichen soll. Für eine vollständige Anleitung zu NSUserActivity empfehle ich Ihnen, einen Blick in die Apple-Dokumentation zu diesem Thema zu werfen.

Wenn es an der Zeit ist, eine Benutzeraktivität bereitzustellen, die zu einem späteren Zeitpunkt wiederhergestellt werden kann, ruft das System die Methode stateRestorationActivity(for:) auf Ihrem SceneDelegate auf. Beachten Sie, dass diese Methode nicht Teil der Standardvorlage ist

func stateRestorationActivity(for scene: UIScene) -> NSUserActivity? { return scene.userActivity}

Damit wird die derzeit aktive Benutzeraktivität für eine Szene mit der Szenensitzung verknüpft. Denken Sie daran, dass jedes Mal, wenn eine Szene getrennt wird, die UISceneSession, die die UIScene besitzt, nicht verworfen wird, damit die Sitzung sich wieder mit einer Szene verbinden kann. Wenn dies geschieht, wird scene(_:willConnectTo:options:) erneut aufgerufen. In dieser Methode haben Sie Zugriff auf die UISceneSession, die die UIScene besitzt, so dass Sie die stateRestorationActivity der Sitzung lesen und den Anwendungsstatus bei Bedarf wiederherstellen können:

if let activity = session.stateRestorationActivity, activity.activityType == "com.donnywals.DocumentEdit", let documentId = activity.userInfo as? String { // find document by ID // create document viewcontroller and present it}

Natürlich werden die feinen Details dieses Codes je nach Ihrer Anwendung variieren, aber die allgemeine Idee sollte klar sein.

Wenn Ihr UISceneSession eine URL verarbeiten soll, können Sie die urlContexts des connectionOptions-Objekts untersuchen, um URLs zu finden, die Ihre Szene öffnen soll, und Informationen darüber, wie Ihre Anwendung dies tun soll:

for urlContext in connectionOptions.urlContexts { let url = urlContext.url let options = urlContext.options // handle url and options as needed}

Das options-Objekt enthält Informationen darüber, ob Ihre Szene die URL an Ort und Stelle öffnen soll, welche Anwendung diese URL angefordert hat und andere Metadaten über die Anforderung.

Die Grundlagen der Zustandswiederherstellung in iOS 13 mit dem SceneDelegate sind überraschend einfach, vor allem da es auf NSUserActivity aufbaut, was bedeutet, dass viele Anwendungen nicht viel Arbeit haben werden, um die Zustandswiederherstellung für ihre Szenen zu unterstützen.

Denken Sie daran, dass die Wiederherstellung von Szenen besonders wichtig ist, wenn Sie Unterstützung für mehrere Szenen für Ihre App auf iPadOS haben möchten, da iOS Ihre Szenen trennen und wieder verbinden könnte, wenn sie vom Vordergrund in den Hintergrund und wieder zurück wechseln. Vor allem, wenn Ihre Anwendung es dem Benutzer erlaubt, Objekte in einer Szene zu erstellen oder zu manipulieren, würde ein Benutzer nicht erwarten, dass seine Arbeit verloren geht, wenn er eine Szene für einen Moment in den Hintergrund verschiebt.

Zusammenfassung

In diesem Blogbeitrag haben Sie viel gelernt. Sie haben gelernt, welche Funktionen AppDelegate und SceneDelegate in iOS 13 erfüllen und wie ihre Lebenszyklen aussehen. Sie wissen jetzt, dass AppDelegate dafür verantwortlich ist, auf Ereignisse auf Anwendungsebene zu reagieren, wie z. B. den Start einer App. Der SceneDelegate ist für Ereignisse im Zusammenhang mit dem Lebenszyklus von Szenen zuständig. Zum Beispiel die Erstellung einer Szene, ihre Zerstörung und die Wiederherstellung des Zustands einer UISceneSession. Mit anderen Worten, der Hauptgrund für Apple, UISceneDelegate zu iOS 13 hinzuzufügen, war, einen guten Einstiegspunkt für Anwendungen mit mehreren Fenstern zu schaffen.

Nachdem Sie die Grundlagen von UISceneDelegate kennengelernt haben, haben Sie ein sehr einfaches Beispiel dafür gesehen, wie die Wiederherstellung des Zustands in iOS 13 mit UISceneSession und UIScene aussieht. Natürlich gibt es noch viel mehr darüber zu lernen, wie sich deine App verhält, wenn ein Benutzer mehrere UISceneSessions für deine App erzeugt, und wie diese Szenen möglicherweise synchron bleiben oder Daten gemeinsam nutzen müssen.

Wenn du mehr über die Unterstützung mehrerer Fenster für deine iPad-App (oder deine macOS-App) erfahren möchtest, sieh dir unbedingt meinen Beitrag Unterstützung für mehrere Fenster zu deiner iPadOS-App hinzufügen an. Danke fürs Lesen, und zögern Sie nicht, mich auf Twitter zu kontaktieren, wenn Sie Fragen oder Feedback haben.

Bleiben Sie mit meinem wöchentlichen Newsletter auf dem Laufenden

Practical Combine

Lernen Sie alles, was Sie über Combine wissen müssen und wie Sie es in Ihren Projekten einsetzen können, in meinem neuen Buch Practical Combine. Sie erhalten dreizehn Kapitel, eine Spielwiese und eine Handvoll Beispielprojekte, die Ihnen helfen, Combine so schnell wie möglich einzusetzen.

Das Buch ist als digitaler Download für nur 29,99 $ erhältlich!

Holen Sie sich Practical Combine

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.