DEV Community

Samuel Owino
Samuel Owino

Posted on

SwiftUI App Life Cycle

iPhone 13 Pro

Xcode offers two options for app life cycle when you open a new Xcode project:

  1. UIKit AppDelegate
  2. SwiftUI

SwiftUI

Projects created with SwiftUI option generate an AppNameApp.swift root file.
This file becomes the app's main entry point.

This file contains a struct that conforms to App protocol

@main
struct TsavoNationalParkApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

ContentView is also added to the main Window.
@main just above the struct declaration tells the system that this is the main entry point in the app.

SwiftUI WindowGroup

A scene that represents a group of identical structured windows.

struct WindowGroup<Content> where Content : View
Enter fullscreen mode Exit fullscreen mode

WindowGroup is used to create a view hierarchy for the app. The hierarchy that you declare for the view's contents serves as template for each window that the view displays.

SwiftUI takes care of platform specific behaviours, for example on macOS and iPadOS, users can open more than one window from the group simulatenously. In macOS users can gather multiple windows together into a tabbed interface.

Every window created from the group maintains independent state. For example, you cannot share State or StateObjects between windows.

@main

main() initializes and runs the application.

If you preceded your app's App Protocol conformer with the @main attribute, the system calls the conformer's main() to launch the app in a system appropriate way.

@main
struct TsavoNationalParkApp: App {
    //window group - scene enclosed
}
Enter fullscreen mode Exit fullscreen mode

Scene

A scene is a part of the operating system with a lifecycle managed by the system.

You create an App by combining one or more instances that conform to the Scene Protocol in the apps's body.
You can use inbuilt scenes such as WindowGroup or compose custom scenes from other scenes.

Create custom scenes by creating a struct that conforms to the scene protocol

struct PlayerSettingScene: Scene {
    var body: some Scene {
        WindowGroup{
            PlayerSettingsContentView()
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

A scene acts as a container for a viwe hierarchy that you want to display to the user. The system descides when and how to display the scene to the user in a way that is platform appropriate.

You can check whether a scene is active or in some other state by reading the scenePhase environment value.

struct PlayerProfileScene: Scene {

    @Environemnt(\.scenePhase) private var scenePhase 

    var bodu: some Scene {
        WindowGroup {
            PlayerProfileContentView()
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

The scene protocol provides scene modifiers, defined as protocol methods with default implementation, that you use to configure the scene

@main
struct PlayerProfileScene: Scene {

    @Environment(\.scenePhase) private var scenePhase

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .onChange(of: scenePhase){ newScenePhase in
            if newScenePhase == ScenePhase.background {
                //empty cache
                //perform some network calls
            }
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

@Environment.PresentationMode

This indicates whether a view has been presented by another view

Depreacated as of iOS 15.5
Apple recommends using isPresented and dismiss environment objects instead

struct ProfileDetailsView: View {

    @Environment(\.presentationMode) private var presentationMode

    var body: some View {
        Button("< Exit") {
            presentationMode.wrappedValue.dismiss() //Close this view
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

@Environment.isPresented

A Boolean value that indicated whether the view is currently presented.

Immutable.

var isPresented: Bool { get }

// Value can be read from the @Environmment property wrapper

@Environment(\.isPresented) private var isPresented
Enter fullscreen mode Exit fullscreen mode

This behaves differently from onAppear() which swift ui can call multiple times such as on back navigation.

@Environment.dismiss

Use property wrapper value to get a handle on the currenct DismissAction instance on the currenct view.

Calling the instance performs the dismiss() action

Immutable

var dismiss: DismissAction { get }
Enter fullscreen mode Exit fullscreen mode
struct WeaponSelectorSheet: View {

    @Environment(\.dismiss) private var dismiss

    var body: some View {
        VStack{
            Label("Select weapon")
            ...

            Button("Save and Resume Game"){
                dismiss()
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)