Warum wird die UIApplicationDelegate-Methode `application (_: configurationForConnecting: options :) nicht zuverlässig aufgerufen?

Aug 21 2020

Problem:

Ich finde ein unerwartetes Verhalten bezüglich der AppDelegate-Methode application(_:configurationForConnecting:options:).

In der Dokumentation heißt es:

UIKit ruft diese Methode kurz vor dem Erstellen einer neuen Szene auf.

Ich würde erwarten, dass dies jedes Mal der Fall ist, wenn die App gestartet wird.
Die Methode wird zwar aufgerufen, wenn ich meine App zum ersten Mal starte, bei allen nachfolgenden Starts jedoch nicht .

Reproduzieren:

Ich habe einen sehr einfachen Testfall zu reproduzieren:

  • Xcode 12> Neues Projekt erstellen> iOS> App (UIKit / Storyboard)
  • Fügen Sie der Methode eine Debugging-Anweisung hinzu AppDelegate:
      // from Apple's sample project:
      func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
          // Called when a new scene session is being created.
          // Use this method to select a configuration to create the new scene with.
          print("I was called!").  // <--- debugging statement
          return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
      }
    
  • starte die App> "Ich wurde gerufen!" wird in der Konsole gedruckt
  • Führen Sie die App erneut aus.> Es wird nichts gedruckt.

Frage:

Warum wird application(_:configurationForConnecting:options:)beim zweiten Start nicht aufgerufen?
(Ist es erwartetes Verhalten, wenn ja warum / Ist es ein Fehler von Apple)

Antworten

3 Adrian Oct 21 2020 at 05:10

Dies scheint ein erwartetes Verhalten zu sein und ist sinnvoll, sobald Sie verstanden haben, was vor sich geht, aber es ist nicht dokumentiert. Ich habe gerade eine ziemlich traumatische Zeit damit verbracht, dem auf den Grund zu gehen. Oh, Apple.

Das Wichtigste ist, dass beim Neustart einer App die Fenster der vorherigen Ausführung wiederhergestellt werden.

(Es ist auch hilfreich, sich daran zu erinnern, dass eine App mehrere Fenstertypen haben kann, die jeweils durch eine Szenenkonfiguration dargestellt werden. Aus diesem Grund können Sie diese Delegatenmethode zunächst implementieren.)

Fall 1: App zum ersten Mal gestartet

Die App weiß nicht, welche Art von Szene in das Fenster eingefügt werden soll, und ruft application(_:configurationForConnecting:options:)an, um dies herauszufinden. Bisher sind die Dinge so, wie wir es erwarten. (Wenn Sie diese Delegatenmethode nicht implementieren, wird nur auf den ersten geeigneten Eintrag in Ihrem Info.plistSzenenmanifest zurückgegriffen, falls vorhanden.)

Fall 2: Neues Fenster erstellt (für Apps, die mehrere Fenster unterstützen)

(z. B. durch Ziehen des Dock-Symbols auf dem iPad). Die App weiß auch nicht, was sie in dieses Fenster einfügen soll. Gleich wie Fall 1.

Fall 3: App neu gestartet

Das Betriebssystem möchte Ihre Fenster wiederherstellen. Zu diesem Zweck wurden die Szenenkonfigurationen der Fenster gespeichert, die Sie zuletzt geöffnet hatten. Überraschung! Es weiß, welche Szenen in die Fenster eingefügt werden sollen, und fragt Ihren App-Delegierten nicht. Es geht einfach weiter und erstellt die Szenen mit den gespeicherten Konfigurationen.

Für den armen Entwickler, der daran denkt, dass beim Start der App ein Fenster erstellt wird, ist dies verwirrend. Wenn Sie jedoch daran denken, dass Fenster beim Start wiederhergestellt und nicht erstellt werden - auch wenn es nur eines gibt -, macht dies Sinn.


Wenn Sie nun Dinge zurücksetzen möchten, damit Ihre Fenster vergessen werden und Ihre Delegatenmethode beim nächsten Start aufgerufen wird:

  • Löschen Sie für iOS die App
  • Löschen Sie für Catalyst den Container der App

Hinweis 1: In Catalyst scheint beim Neustart nur das erste Fenster wiederhergestellt zu werden, ansonsten ist das Verhalten das gleiche wie oben. Habe jetzt beobachtet, dass dies nicht wahr ist. Vielleicht ist es inkonsistent.

Hinweis 2: Sie können auch den Inhalt Ihrer Fenster wiederherstellen , nicht nur deren Typ , mit UIWindowSceneDelegateund UISceneSession.stateRestorationActivity, aber das ist eine andere Geschichte.