147 votes

Cycle de vie des applications SwiftUI iOS14 : où mettre le code AppDelegate ?

Maintenant que AppDelegate y SceneDelegate sont supprimées de SwiftUI, où dois-je mettre le code que j'avais auparavant dans SceneDelegate y AppDelegate La configuration de Firebase, par exemple ?

J'ai donc ce code actuellement dans mon AppDelegate :

Où dois-je mettre ce code maintenant ?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

    FirebaseConfiguration.shared.setLoggerLevel(.min)
    FirebaseApp.configure()
    return true
}

144voto

Asperi Points 123157

Voici une solution pour le cycle de vie de SwiftUI. Testé avec Xcode 12b / iOS 14

import SwiftUI
import UIKit

// no changes in your AppDelegate class
class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        print(">> your code here !!")
        return true
    }
}

@main
struct Testing_SwiftUI2App: App {

    // inject into SwiftUI life-cycle via adaptor !!!
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

0 votes

Génial, une idée de comment mettre à jour une application existante pour utiliser le cycle de vie de SwiftUI ?

5 votes

@RexhinHoxha, définissez la cible de déploiement à iOS 14, enlevez @UIApplicationMain de AppDelegate, et ajouter is-a App structure comme ci-dessus.

0 votes

Désolé, je sais que cette question est un peu ancienne mais j'essaie de l'utiliser pour changer l'arrière-plan de la barre de navigation. Est-ce que cela peut être fait avec SwiftUI en mettant la commande normale UINavigationBar.appearance().barTintColor = UIColor.red où il est dit >> your code here !!

98voto

Peter Friese Points 433

Le remplacement de l'initialisateur dans votre App fonctionne également :

import SwiftUI
import Firebase

@main
struct BookSpineApp: App {

  init() {
    FirebaseApp.configure()
  }

  var body: some Scene {
    WindowGroup {
      BooksListView()
    }
  }
}

Vous trouverez un compte rendu plus détaillé ici :

47voto

Mojtaba Hosseini Points 2525

Vous ne devez pas du tout mettre ce genre de codes dans le délégué d'application, sinon vous vous retrouverez face à l'erreur suivante Délégué de Massive App . Vous devriez plutôt envisager de refactoriser votre code en morceaux plus significatifs, puis de placer la bonne partie au bon endroit. Dans ce cas, la seule chose dont vous avez besoin est d'être sûr que le code exécute ces fonctions une fois que l'application est prête et une seule fois. Ainsi, le init La méthode pourrait être géniale :

@main
struct MyApp: App {
    init() {
        setupFirebase()
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

private extension MyApp {
    func setupFirebase() {
        FirebaseConfiguration.shared.setLoggerLevel(.min)
        FirebaseApp.configure()
    }
}

AppDelegate ?

Vous pouvez avoir votre propre classe personnalisée et l'assigner en tant que delegate . Mais notez que cela ne fonctionnera pas pour les événements qui se produisent avant l'affectation. Par exemple :

class CustomDelegate: NSObject, UIApplicationDelegate {
    static let Shared = CustomDelegate()
}

Et plus tard :

UIApplication.shared.delegate = CustomDelegate.Shared

Observer pour les notifications

La plupart des AppDelegate sont en fait des méthodes d'observation sur des notifications que vous pouvez observer manuellement au lieu de définir une nouvelle classe. Par exemple :

NotificationCenter.default.addObserver(
    self,
    selector: #selector(<#T##@objc method#>),
    name: UIApplication.didBecomeActiveNotification,
    object: nil
)

Native AppDelegate Wrapper

Vous pouvez injecter directement un délégué d'application dans le @main struct :

@UIApplicationDelegateAdaptor(CustomDelegate.self) var appDelegate

Remarque : L'utilisation de AppDelegate

N'oubliez pas que l'ajout d'AppDelegate signifie que vous supprimez la prise en charge multiplateforme par défaut et que vous devez vérifier la plateforme manuellement.

22voto

MScottWaller Points 81

Vous pouvez également utiliser la nouvelle ScenePhase pour certains codes que les AppDelegate et SceneDelegate avaient. Comme passer à l'arrière-plan ou devenir actif. À partir de

struct PodcastScene: Scene {
    @Environment(\.scenePhase) private var phase

    var body: some Scene {
        WindowGroup {
            TabView {
                LibraryView()
                DiscoverView()
                SearchView()
            }
        }
        .onChange(of: phase) { newPhase in
            switch newPhase {
            case .active:
                // App became active
            case .inactive:
                // App became inactive
            case .background:
                // App is running in the background
            @unknown default:
                // Fallback for future cases
            }
        }
    }
}

Exemple de crédit : https://wwdcbysundell.com/2020/building-entire-apps-with-swiftui/

0 votes

Je reçois 'Failed to get FirebaseApp instance. Please call FirebaseApp.configure() before using Firestore' terminating with uncaught exception of type NSException quand je mets FirebaseApp.configure() en cas de .active :

0 votes

Vous pouvez essayer de configurer Firebase en utilisant l'option init() { FirebaseApp.configure() } Comme indiqué dans l'une des autres réponses

6voto

anon Points 108

Je vois beaucoup de solutions où init est utilisé comme didFinishLaunching . Cependant, didFinishLaunching est appelé APRÈS init de la App struct.

Au lieu de cela, nous pouvons créer un bloc pour nous avertir lorsque didFinishLaunching est appelé. Cela permet de garder plus de code dans le monde de SwiftUI (plutôt que dans le monde de AppDelegate ).

class AppDelegate: NSObject, UIApplicationDelegate {

  var didFinishLaunching: ((AppDelegate) -> Void)?

  func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions
      launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
  ) -> Bool {
    didFinishLaunching?(self)
    return true
  }
}

@main
struct MyApp: App {
  @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

  @ObservedObject private var applicationModel = ApplicationModel()

  // `init` gets called BEFORE `didFinishLaunchingWithOptions`
  init() {

    // Subscribe to get a `didFinishLaunching` call
    appDelegate.didFinishLaunching = { [weak applicationObject] appDelegate in

      // Setup any application code...
      applicationModel?.setup()
    }
  }

  var body: some Scene {
    return WindowGroup {
      if applicationObject.isUserLoggedIn {
        LoggedInView()
      } else {
        LoggedOutView()
      }
    }
  }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X