Friday, July 2, 2021

SwiftUI Scene delegate vs App

Earlier to App, To display a view made with SwiftUI, you had to wrap it in a UIHostingController, which had to be wrapped in a UIWindow, which had to be defined in SceneDelegate:


import UIKit

import SwiftUI


// Auto-generated code

class SceneDelegate: UIResponder, UIWindowSceneDelegate {


    var window: UIWindow?


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.

        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.

        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).

        // Create the SwiftUI view that provides the window contents.

        let contentView = ContentView()


        // Use a UIHostingController as window root view controller.

        if let windowScene = scene as? UIWindowScene {

            let window = UIWindow(windowScene: windowScene)

            window.rootViewController = UIHostingController(rootView: contentView)

            self.window = window

            window.makeKeyAndVisible()

        }

    }

    ... Lots more code!

}



 at WWDC20, a solution was announced: App.

import SwiftUI


@main

struct HelloWorldApp: App {

    var body: some Scene {

        WindowGroup {

            ContentView()

        }

    }

}




It looks very, very similar to our HelloWorldApp struct! There are some differences, however:

@main tells Xcode that the following struct, HelloWorldApp, will be the entry point for the app. Only one struct can be marked with this attribute.

According to the documentation, App is a protocol that “represents the structure and behavior of an app.” HelloWorldApp conforms to this. It’s like the base view of your app — no, the app itself. You’re literally writing out what your app will look like in this struct.

Scene — The body of a SwiftUI View must be of type View. Similarly, the body of a SwiftUI App must be of type Scene…


And because platforms like macOS and iPadOS support multiple windows, wrapping all your app’s views in a Scene makes reusability easier while also allowing for “Scene Phases” that include active, inactive, and background states.

WindowGroup is a Scene that wraps views. The view that we want to present, ContentView, is a View — not a scene. WindowGroup lets us wrap them up into a single Scene that SwiftUI can recognize and display.



In the new App protocol, Apple made sure that even the optional parts of the life cycle — those that not many will use — are still super easy to implement:




@main

struct HelloWorldApp: App {

    @Environment(\.scenePhase) private var scenePhase

    var body: some Scene {

        WindowGroup {

            ContentView()

        }

        .onChange(of: scenePhase) { (newScenePhase) in

            switch newScenePhase {

            case .active:

                print("scene is now active!")

            case .inactive:

                print("scene is now inactive!")

            case .background:

                print("scene is now in the background!")

            @unknown default:

                print("Apple must have added something new!")

            }

        }

    }

}



Also, sometimes you still need AppDelegate (for things like Firebase and home screen quick actions). In this case, you can continue using the App protocol — just extend it with @UIApplicationDelegateAdaptor.




references:

https://betterprogramming.pub/say-goodbye-to-scenedelegate-in-swiftui-444173b23015

No comments:

Post a Comment