With the launch of SwiftUI 2 at WWDC 2020, Apple introduced a new App Life Cycle (App). Instead of an AppDelegate.

Application gateways

When creating a new SwiftUI application, the main class of the application looks like this:

import SwiftUI

@main
struct SwiftUIApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()}}}Copy the code

Initialize the configuration and third-party libraries

In most cases, the application starts with initialization: default data configuration, SDKS, third-party libraries, and so on.

When using AppDelegate in application (_ application: didFinishLaunchingWithOptions launchOptions:) operation:

func application(_ application: UIApplication.didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // configs...
        print("Application is starting...")
        return true
    }
Copy the code

In the life cycle of the App:

import SwiftUI

@main
struct SwiftUIApp: App {

  init(a) {
        // configs...
        print("Application is starting...")}var body: some Scene {
    WindowGroup {
      ContentView()}}}Copy the code

Handles the application lifecycle

Sometimes we need to deal with operations based on the life cycle of the application. For example, we want to refresh the data when the application is active, or cache the data when the application is in background state.

In the AppDelegate, realize applicationWillResignActive, applicationDidBecomeActive, applicationWillEnterForeground, ApplicationDidEnterBackground, applicationWillTerminate method

In the App, Apple provides a new API: ScenePhase

SwiftUI tracks the state of the application. You can use the @Environment attribute wrapper to get the current value and use.onchange (of: Perform 🙂 to listen for changes.

import SwiftUI

@main
struct SwiftUIAppApp: App {
    
    @Environment(\.scenePhase) var scenePhase

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .onChange(of: scenePhase) { phase in
            switch phase {
            case .active:
                print("Application is active")
            case .inactive:
                print("Application is inactive")
            case .background:
                print("Application is background")
            default:
                print("unexpected value.")}}}}Copy the code

It’s worth noting that other locations in the app can also use this method of listening:

import SwiftUI

struct ContentView: View {
    
    @Environment(\.scenePhase) private var scenePhase
    
    var body: some View {
        Text("Hello, world!")
            .padding()
            .onChange(of: scenePhase, perform: { value in
                if value = = .active {
                    print("Application view is active...")}})}}Copy the code

Isn’t that nice? Imagine the process of writing a notice…

Notice: I don’t want face

Dealing with Deep Link

In the AppDelegate, implement application(_:open:options:) to process the URL

In the App, use the.onOpenURL modifier.

import SwiftUI

@main
struct SwiftUIAppApp: App {

    var body: some Scene {
        WindowGroup {
            ContentView()
                
                .onOpenURL(perform: { url in
                    print("Received URL: \(url)")})}}}Copy the code

Similarly, you can apply this modifier elsewhere in the application. That means you can handle deep links anywhere. Of course, the premise is that when the application starts, the implementation position must be in the active state

import SwiftUI

struct ContentView: View {

    var body: some View {
        Text("Hello, world!")
            .onOpenURL(perform: { url in
                print("Received URL: \(url)")}}}Copy the code

Although universal Links should be used after iOS 9, it is more secure. But that doesn’t deny the convenience of onOpenURL. We can still define and use it.

The terminal invokes the App via deep link:

xcrun simctl openurl booted your url

I don’t care. I’m just going to use an AppDelegate

So when you create the project, you chooseAppDelegateCough up. A little bit…

The life cycle of an App is not a complete substitute for an AppDelegate, and in some cases we still need to use an AppDelegate or its methods. For example: SDK callback, third-party library Extension, Method Swizzling, etc.

Provides a comprehensive a variety of reasons, Swift AppDelegate method, which is connected with the App: @ UIApplicationDelegateAdaptor

import SwiftUI

class AppDelegate: NSObject.UIApplicationDelegate {
    func application(_ application: UIApplication.didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        print("Application didFinishLaunchingWithOptions")
        return true
    }

    func application(_ application: UIApplication.willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        print("willFinishLaunchingWithOptions")
        return true}}@main
struct SwiftUIAppApp: App {
    
    @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
    
    init(a) {
        print("Application is starting...")}var body: some Scene {
        WindowGroup {
            ContentView()}}}Copy the code

conclusion

SwiftUI 2’s new app entry is designed, in part, to simplify app launch. At a glance, it is very simple, but also convenient for others to take over when easier to be clear at a glance, easy to maintain. All in all, it’s good.

There are also some disadvantages. At present, compared to the AppDelegate, the App is not perfect, and some functions still rely on interaction with the AppDelegate. There are few official demos, and most of them have to be worked out on their own. Look forward to the follow-up official website supplement and update! And it’s only the beginning, after all. Swift went through five versions before settling down. SwiftUI is young by comparison.

Demo

Github

Reference:

  • The Ultimate Guide to the SwiftUI 2 Application Life Cycle