SwiftUI App Structure

SwiftUI 与传统的 UIKit 思路不同,是一种声明式 UI 框架,这种框架的特点就是摒弃了传统开发的代码按生命周期进行的流程概念,直接通过声明所呈现的内容来与用户进行交互。

App

swift 复制代码
protocol App

App 代表了应用程序的抽象,需要在它的 body 属性中声明应用所能够呈现的内容:

swift 复制代码
@main 
struct MyApp: App { 
    var body: some Scene { 
        WindowGroup { 
            Text("Hello, world!") 
        } 
    } 
}

在你的自定义实现结构体声明之上添加 @main,用来标记这是应用程序的唯一主入口。同时,这也意味着你的应用程序只能有这一个主入口。

Scene

App 的 body 属性中,可以组合一个或多个 Scene 的实现,每一个 Scene 实现包含视图结构的根视图,代表用户界面中的内容,也可能是一部分(多窗口),它的生命周期由系统管理。

SwiftUI 提供了一些 Scene 的实现来表示场景的场景,包括显示设置或是文档。 你也可以自定义创建 Scene,但其实就是组合一些系统提供的 Scene:

swift 复制代码
struct MyScene: Scene {
    var body: some Scene {
        WindowGroup {
            MyRootView()
        }
    }
}

Scene 有一些常见实现:

  • WindowGroup
  • Settings
  • Window
  • ImmersiveSpace
  • DocumentGroup
  • ...

SwiftUI 是跨平台框架,所以基于不同的平台支持的 Scene 也有所不同。例如,visionOS 不支持 Window,而 ImmersiveSpace 是 visionOS 独有的。

App 的 body 中可以容纳一个或多个 Scene:

swift 复制代码
@main
struct Mail: App {

    var body: some Scene {
        WindowGroup {
            MailViewer()
        }
        Settings {
            SettingsView() 
        }
    }
}

应用启动,会默认打开第一个 Scene 所呈现的内容 。针对不同的平台,可能需要修改 plist 来支持多场景。例如,在 visionOS 平台或 iPadOS,需要添加 Enable Mutiple Windows 为 YES。

Scene 本质上就是呈现 View 结构的容器,系统会决定他们的显示行为,例如,在 iPadOS 或 macOS 支持多窗口,用户就可以创建或是删除一些窗口;而在 iOS 平台(or 其他)当应用处于活跃状态,视图内容将会占满整个屏幕。

Scene 的生命周期

可以通过环境值 scenePhase 来从 Scene 或 View 中读取当前 Scene 是否处于活跃状态:

swift 复制代码
struct MyScene: Scene {
    @Environment(\.scenePhase) private var scenePhase


    // ...
}

scenePhase 是枚举类型 ScenePhase,包括:

  • background:处于后台,不可交互;
  • inactive:处于前台,不可交互;
  • active:处于前台,可以交互。

Scene 提供了一些方法,可以对 Scene 进行配置,例如可以使用 onChange(of:perform) 来监听某个值的变化,从而触发一些操作,下面是一个当应用进入后台后清除缓存的操作:

swift 复制代码
struct MyScene: Scene {
    @Environment(\.scenePhase) private var scenePhase
    @StateObject private var cache = DataCache()


    var body: some Scene {
        WindowGroup {
            MyRootView()
        }
        .onChange(of: scenePhase) { newScenePhase in
            if newScenePhase == .background {
                cache.empty()
            }
        }
    }
}

Scene 之间的通信

多个 Scene 可以通过在 App 中声明一些状态来进行通信。例如,使用 @StateObject 来初始化一个数据类,然后将数据类作为 ObservedObject 或通过环境作为 EnvironmentObject 提供给 Scene:

swift 复制代码
@main
struct Mail: App {
    @StateObject private var model = MailModel()


    var body: some Scene {
        WindowGroup {
            MailViewer()
                .environmentObject(model) // Passed through the environment.
        }
        Settings {
            SettingsView(model: model) // Passed as an observed object.
        }
    }
}

总结

SwiftUI App 以 App 协议的实现为应用主入口,其 body 属性中可以配置多个 Scene,App 启动时默认打开第一个 Scene。 Scene 代表用户界面的容器,用来承载视图结构,其内容是视图结构的根视图。Scene 具有生命周期,包括三种:

  1. backgroud
  2. inactive
  3. active 可以通过环境属性 scenePhase 来查询。 Scene 直接可以通过在 App 中定义共享的数据结构来共享数据。可以通过一些方法或通过参数的形式传递到不同的 Scene。
相关推荐
小溪彼岸2 天前
【iOS小组件】小组件尺寸及类型适配
swiftui·swift
文件夹__iOS7 天前
[SwiftUI 开发] @dynamicCallable 与 callAsFunction:将类型实例作为函数调用
ios·swiftui·swift
小溪彼岸7 天前
【iOS小组件】iOS17与低版本兼容适配
swiftui·swift
Mamong8 天前
SwiftUI疑难杂症(1):sheet content多次执行
ios·swiftui·swift
AUV110712 天前
Mac剪贴板历史全记录!
macos·swiftui·mac·效率工具·实用工具·剪贴板·clipboard
AUV110712 天前
Mac 上哪个剪切板增强工具比较好用? 好用剪切板工具推荐
macos·swiftui·mac·剪贴板·clipboard·剪贴板增强·app 推荐
多彩电脑14 天前
SwiftUI里的ForEach使用的注意事项
macos·ios·swiftui·swift
Swift社区16 天前
Apple 新品发布会亮点有哪些 | Swift 周报 issue 61
ios·swiftui·swift
humiaor17 天前
Xcode报错:No exact matches in reference to static method ‘buildExpression‘
swiftui·xcode
humiaor25 天前
Xcode报错:Return from initializer without initializing all stored properties
swiftui·binding