iT邦幫忙

2021 iThome 鐵人賽

DAY 12
0
Software Development

iOS 學習筆記系列 第 12

Day12 SwiftUI 05 - Life Cycle - SwiftUI App

Life Cycle - SwiftUI App

如前面所介紹的,在Xcode 12 創建新的 SwiftUI 專案視窗,在初始配置有一個改變,就是多了 Life Cycle 選單,前面我們新增過 UIKit App Delegate 的專案了,這邊我們就來新增看看 SwiftUI App 的專案

https://ithelp.ithome.com.tw/upload/images/20210927/20118479DLl7PRCbBw.png

新建完成後,我們來看一下它自動產生的檔案,來跟前面的 Life Cycle - UIKit App Delegate 專案比較,發現專案沒有 AppDelegateSceneDelegate來處理 App 的生命週期及其各種狀態了,代替的是一個與專案名字相同的檔案,加上 "App" 後綴,例如HelloWorldApp.swift 檔案:

https://ithelp.ithome.com.tw/upload/images/20210927/20118479H7gGXaD7ym.png

我們來看看這些修改做了些什麼

  • App 的 entry point 是採用 App 框架的結構 (structure),這是一種全新的型別,根據 Apple 官方文件,「App是一種協定,代表了 App 的結構和行為」,它取代了原本的 AppDelegate,並接管了它的許多功能
  • HelloWorldApp.swift 中 HelloWorldApp struct 被加了 @main 屬性標記,以表示這是 App 的 entry point,而且不可能會有多於一個結構被這樣標記,它將在調用時初始化應用程序
  • 結構的 body 型別為 Scene,這是另一個協定,根據官方文件,它是一個要顯示給使用者的視圖層次結構 (view hierarchy) 的容器。每個場景都包含視圖層次結構的根視圖,並具有由系統管理的生命週期
  • WindowGroup 是一個包裝視圖的場景,它是一個跨平台的結構,代表一個多窗口的場景,你可以在 macOS、iOS 等上使用它,它是你的應用程序視圖層次結構的容器
  • 在 WindowGroup 中,需要為應用程序聲明第一個視圖,而我們要呈現的視圖ContentView 是一個View,而不是一個場景,WindowGroup 使我們可以將它們包裝到SwiftUI 可以識別和顯示的單個場景中

SwiftUI 將整個原有的平台差異部分抽象為 App 和Scene,對於一個mac/iOS/iPad/watch/tv/..應用程序來說,App 代表了整個應用,Scene 代表了與Window 相關的多窗口,有些設備只有一個Scene 有些則有多個,雖然不同的OS 確實存在差異,但是在語義層面達到了一致

以下我們再對 SwiftUI App 或 SwiftUI App Lifecycle 做進一步的介紹

  1. App States Callbacks

    在 iOS 14 中,Apple 提供了 ScenePhase 來追蹤應用程序的狀態。 場景的狀態在環境中被追蹤,因此我們創建了 @Environment 屬性來訪問當前值,然後使用 onChange(of:) 修飾符來監聽狀態的任何變化。

    @main
    struct HelloWorldApp: App {
        @Environment(\.scenePhase) var scenePhase
    
        var body: some Scene {
            WindowGroup {
                ContentView()
            }.onChange(of: scenePhase) { (newScenePhase) in
                switch newScenePhase {
                case .background:
                    print("App State : Background")
                case .inactive:
                    print("App State : Inactive")
                case .active:
                    print("App State : Active")
                @unknown default:
                    print("App State : Unknown")
                }
            }
        }
    }
    
    

    有關更多詳細信息,請參考官方文件

  2. Deeplink URLs

    在 UIKit 方法中,我們通過在AppDelegate 中 回調application(_:open:options:)方法處理所有深層鏈接 url,但是在 SwiftUI 中,我們可以通過將 onOpenURL 修飾符附加到應用程序的最頂層場景來處理傳入的 url。 它在閉包中返回傳入的 url

                ContentView()
                    .onOpenURL(perform: { url in
                        print("Incoming url: \(url)")
                    })
    
  3. App Init

    對於基本初始化,可以像在 AppDelegate 的 didFinishLaunchWithOptions 方法中一樣執行初始化,或者如果您正在使用某些第三方並且需要在應用程序啟動時進行設置, SwiftUI App 換在 struct HelloWorldAppinit 方法中進行初始化操作

    範例:

    @main
    struct HelloWorldApp: App {
        @Environment(\.scenePhase) var scenePhase
    
        init() {
            // perform any task on app launch
        }
    
        var body: some Scene {
            WindowGroup {
                ContentView()
                    .onOpenURL(perform: { url in
                        print("Incoming url: \(url)")
                    })
            }.onChange(of: scenePhase) { (newScenePhase) in
                switch newScenePhase {
                case .background:
                    print("App State : Background")
                case .inactive:
                    print("App State : Inactive")
                case .active:
                    print("App State : Active")
                @unknown default:
                    print("App State : Unknown")
                }
            }
        }
    }
    
  4. AppDelegate in SwiftUI

    如果您有一些需求一定要用到 AppDelegate 的話,那麼 SwiftUI 提供了一種通過使用 @UIApplicationDelegateAdaptor 在 SwiftUI 生命週期內使用 AppDelegate 的方法

    @UIApplicationDelegateAdaptor 提供了使用 UIApplicationDelegate 方法的選項,這些方法通常在 UIKit 應用程序中使用

    首先添加一個文件來創建 AppDelegate 類別,例如創建一個"MyAppDelegate.swift"後,裡面內容為 "MyAppDelegate" 類別,它繼承自 "UIResponder" 並有實作 "UIApplicationDelegate" 協定,然後添加didFinishLaunchWithOptions方法

https://ithelp.ithome.com.tw/upload/images/20210927/20118479lIe3jKJvH2.png

創建 AppDelegate 後,現在通過 @UIApplicationDelegateAdaptor 屬性包裝器將其附加到結構 "HelloWorldApp" 的入口點

https://ithelp.ithome.com.tw/upload/images/20210927/20118479KUm9rU0fRd.png

在調用場景 init 方法後,即會調用 AppDelegate 的 didFinishLaunchWithOptions 方法。

以上就簡單介紹了關於新的 SwiftUI 生命週期更新的基礎

參考文件:Bye Bye AppDelegate! SwiftUI App Life Cycle


上一篇
Day11 SwiftUI 04 - 在SwiftUI 上設計多畫面
下一篇
Day13 SwiftUI 06 - WebView
系列文
iOS 學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言