Los desarrolladores Apple estamos todavía “de resaca” después de la WWDC 20 donde se presentaron las últimas novedades en cuanto a desarrollo en las plataformas de la manzana, que estarán disponibles para los usuarios a finales de año.

Sin embargo, son tantas las novedades que se presentan cada año (aunque últimamente parece que la gente se queda siempre con ganas de más) que realmente es prácticamente imposible estar al día de todas, y algunas pasan bastante desapercibidas hasta un tiempo después, aunque tengan una importancia notable.

Un ejemplo de esto, son los cambios en el ciclo de vida que Apple introdujo en la versión 13 de iOS y iPadOS. Al ser algo que no afecta directamente a aplicaciones antiguas, o iniciadas antes de dicha versión del SO, muchísimos desarrolladores (entre los que me incluyo) no reparamos en este cambio.

Sin embargo, es más importante de lo que puede parecer en un primer momento, por lo que vamos a darle un pequeño repaso.

¿No te ha pasado que al iniciar un nuevo proyecto iOS/iPadOS en XCode11+ aparece un archivo “nuevo” llamado Scene Delegate? Quizá no le has dado mucha importancia, has continuado desarrollando y no has notado nada raro.

O, por el contrario, te ha dado problemas y has buscado la forma de quitártelo de en medio pero realmente no sabes para qué servía… ¿No te quedaste con la curiosidad? Sigue leyendo...

App Delegate vs Scene Delegate

Hasta iOS12, las aplicaciones se comunicaban con el sistema mediante el App Delegate, el cual tenía dos responsabilidades principales:

Lo que estaba bien hasta ese momento, ya que las apps solo tenían un proceso y un estado de UI que manejar.

Sin embargo, a partir de iOS/iPadOS 13, este patrón deja de ser válido ya que las aplicaciones, aunque van a seguir compartiendo un único proceso, podrían tener varias instancias de interfaz de usuario simultáneamente en iPadOS y macOS (recordemos que podemos desarrollar apps compatibles con macOS utilizando UIKit gracias a Catalyst).

Por ello, se libera al App Delegate de todo lo relativo a la UI y esas responsabilidades las hereda el nuevo Scene Delegate.

Así, si nuestra app se ejecuta en iOS12 o anteriores, debemos manejar los dos ciclos de vida en el App Delegate, mientras que en versiones posteriores lo recomendado (sobretodo si nuestra app también se ejecutará en ipadOS) es hacerlo con la ayuda del Scene Delegate, aunque no es obligatorio.

Para activarlo debemos añadir la clave UIApplicationSceneManifest al Info.plist de nuestra app y proveer la configuración de las posibles escenas estáticamente en el info.plist o dinámicamente con un método tal y como se indica en la documentación oficial.

Compatibilidad en versiones anteriores

Como comentaba al principio, a partir de XCode 11 las plantillas para empezar una aplicación que nos ofrece el IDE ya adoptan el soporte a Scenes por defecto, pero… no da ningún soporte para versiones anteriores.

En el momento que cambiemos el “Deployment Target” a una versión anterior a la 13, empiezan a aparecer errores de compilación.

Para solucionar estos errores muchos desarrolladores tras una búsqueda rápida optan por desactivar el soporte a Scenes. Sin embargo, es posible convivir con los dos sistemas y no morir en el intento.

Para ello, podemos incluir código en el método application:didFinishLaunchingWithOptions del Appdelegate que diferencia si se está ejecutando en un SO anterior o posterior a la versión 13 y maneja la inicialización de la UI y el ciclo de vida como corresponda en cada caso.

Por ejemplo, si utilizamos xib este podría ser un punto de partida:

// Begin UI
if #available(iOS 13.0, *) {
    // In iOS13+ SceneDelegate will start the UI and manage its lifecycle
} else { 
    window = UIWindow(frame: UIScreen.main.bounds)

    let viewController = MyViewControllerInitializer()
    window?.rootviewController = viewController 
    window?.makeKeyAndVisible
}

En el Scene Delegate bastaría con incluir anotaciones para hacerle saber al compilador que solo se utilizará en versiones compatibles, e iniciaríamos la UI dentro del método scene:willConnectTo:options del mismo modo:

@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }

        window = UIWindow(windowScene: windowScene)

        let viewController = MyViewControllerInitializer()
        window?.rootviewController = viewController 
        window?.makeKeyAndVisible

    }
…

Entonces… ¿El futuro es usar Scene Delegate?

Pues la verdad es que yo no apostaría por ello.

Todo apunta que el futuro del desarrollo Apple, en lo que a diseño de interfaces gráficas se refiere, irá de la mano del nuevo framework SwiftUI (también introducido en la WWDC19 y vitaminado en la reciente WWDC20).

Si aún no lo conoces en este post te contamos todos lo que necesitas saber sobre SwiftUI y el futuro de la programación en el ecosistema Apple. Aunque, para aplicaciones que necesiten soporte para versiones anteriores no nos queda otra que seguir usando UIKit.

Así pues, considera adaptar tus aplicaciones existentes a Scenes si tienen compatibilidad con iPad y además quieres darles soporte para múltiples ventanas; en caso contrario, quizá no merezca la pena el esfuerzo.

Si por el contrario te dispones a iniciar un nuevo proyecto y necesitas la compatibilidad con versiones anteriores a la 12, ya sabes qué es ese Scene Delegate que ha aparecido de repente y por qué está ahí, tu decides si adoptarlo o… “hacerlo a la vieja usanza”.

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.

Suscríbete

Estamos comprometidos.

Tecnología, personas e impacto positivo.