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。
相关推荐
今天也想MK代码2 天前
在Swift开发中简化应用程序发布与权限管理的解决方案——SparkleEasy
前端·javascript·chrome·macos·electron·swiftui
東三城8 天前
【ios】---SwiftUI开发从入门到放弃
ios·swiftui·swift·1024程序员节
今天也想MK代码10 天前
基于swiftui 实现3D loading 动画效果
ios·swiftui·swift
胖虎111 天前
SwiftUI(五)- ForEach循环创建视图&尺寸类&安全区域
ios·swiftui·swift·foreach·安全区域
zyosasa17 天前
SwiftUI 精通之路 11: 栅格布局
前端·swiftui·swift
小溪彼岸21 天前
【iOS小组件实战】灵动岛实时进度通知
swiftui·swift
提笔忘字的帝国25 天前
【ios】SwiftUI 混用 UIKit 的 Bug 解决:UITableView 无法滚动到底部
swiftui·bug·xcode
zyosasa25 天前
SwiftUI 精通之路 09:ForEach 视图构造器的基础应用
swiftui·swift
提笔忘字的帝国25 天前
【ios】在 SwiftUI 中实现可随时调用的加载框
ios·swiftui·xcode·swift
小溪彼岸25 天前
【iOS小组件】小组件App ID、Group ID、描述文件
swiftui·swift