¿Por qué el método UIApplicationDelegate `application (_: configurationForConnecting: options:)` no se llama de manera confiable

Aug 21 2020

Problema:

Encuentro un comportamiento inesperado con respecto al método AppDelegate application(_:configurationForConnecting:options:).

La documentación dice:

UIKit llama a este método poco antes de crear una nueva escena.

Espero que este sea el caso cada vez que se lanza la aplicación.
De hecho, se llama al método cuando lanzo mi aplicación por primera vez, sin embargo, para todos los lanzamientos posteriores, no lo es .

Reproducir:

Tengo un caso de prueba muy simple para reproducir:

  • Xcode 12> Crear nuevo proyecto> iOS> Aplicación (UIKit / Storyboard)
  • agregue una declaración de depuración en el método de la siguiente AppDelegatemanera:
      // 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)
      }
    
  • ejecutar la aplicación> "¡Me llamaron!" se imprime en la consola
  • ejecute la aplicación de nuevo> no se imprime nada.

Pregunta:

¿Por qué application(_:configurationForConnecting:options:)no se llama para el segundo lanzamiento?
(¿Es el comportamiento esperado? En caso afirmativo, ¿por qué? ¿Es un error de Apple?)

Respuestas

3 Adrian Oct 21 2020 at 05:10

Este parece ser un comportamiento esperado y tiene sentido una vez que comprende lo que está sucediendo, pero no está documentado. Acabo de pasar un tiempo bastante traumático llegando al fondo del asunto. Oh, Apple.

La clave que debe saber es que cuando reinicia una aplicación, se restauran las ventanas de la ejecución anterior.

(También ayuda recordar que una aplicación puede tener varios tipos de ventana, cada una representada por una configuración de escena, por lo que puede implementar este método delegado en primer lugar).

Caso 1: aplicación lanzada por primera vez

La aplicación no sabe qué tipo de escena poner en la ventana y llama application(_:configurationForConnecting:options:)para averiguarlo. Hasta ahora las cosas son como esperamos. (Si no implementa este método delegado, simplemente recurre a la primera entrada adecuada en el Info.plistmanifiesto de su escena, si tiene una).

Caso 2: Nueva ventana creada (para aplicaciones que admiten múltiples ventanas)

(por ejemplo, arrastrando el icono de la base en el iPad). La aplicación tampoco sabe qué poner en esta ventana. Igual que en el caso 1.

Caso 3: Aplicación relanzada

El sistema operativo quiere restaurar sus ventanas. Para hacer esto, ha recordado las configuraciones de escena de las ventanas que abrió la última vez. ¡Sorpresa! Sabe qué escenas poner en las ventanas y no le pregunta al delegado de su aplicación. Simplemente sigue adelante y crea las escenas usando las configuraciones recordadas.

Para el desarrollador pobre que piensa en términos de la creación de una ventana cuando se inicia la aplicación, esto es confuso. Pero si piensa que las ventanas se restauran al inicio, no se crean, incluso cuando solo hay una, comienza a tener sentido.


Ahora, si desea restablecer las cosas para que se olviden sus ventanas y se llame a su método delegado en el próximo lanzamiento:

  • para iOS, elimine la aplicación
  • para Catalyst, elimine el contenedor de la aplicación

Nota 1: En Catalyst, parece que solo se restaura la primera ventana al reiniciar, pero por lo demás, el comportamiento es el mismo que el anterior. Ahora he observado que esto no es cierto. Quizás sea inconsistente.

Nota 2: También puede restaurar el contenido de su Windows , no solo su tipo , usando UIWindowSceneDelegatey UISceneSession.stateRestorationActivity, pero esa es otra historia.