SwiftUI 中的 App 基础
App essentials in SwiftUI
2020年6月22日
一句话判断
SwiftUI 终于有了自己的 App 协议——不再需要 UIKit 的 AppDelegate/SceneDelegate 样板代码,一个纯 SwiftUI App 可以从不到 10 行代码开始,这是 SwiftUI 从”UI 框架”升级为”全栈框架”的标志。
这场 Session 讲了什么
iOS 14 引入了 App 协议和 Scene 协议,让 SwiftUI App 可以完全脱离 UIKit 的生命周期管理。过去即使是 SwiftUI 项目也需要 AppDelegate 和 SceneDelegate 来处理启动、前后台切换等事件,现在这些都可以在 SwiftUI 中声明式地完成。
核心 API:@main 标注的 App 结构体是整个 App 的入口,body 属性返回 Scene,Scene 内包含 View。WindowGroup 是最常用的 Scene 类型,自动处理多窗口(iPadOS)、状态恢复等系统行为。
Session 还介绍了 @UIApplicationDelegateAdaptor(在 SwiftUI 中桥接 AppDelegate),@Environment 的新值(如 \.scenePhase 用于监听前后台切换),以及 Settings Scene(macOS 上的偏好设置窗口)。
值得深挖的点
从命令式生命周期到声明式。 过去你在 AppDelegate 的 didFinishLaunching 中配置全局状态,在 didEnterBackground 中保存数据。SwiftUI 的方式是在 body 中声明 App 的 Scene 结构,在 View 中用 @Environment(\.scenePhase) 响应状态变化。这种转变把”做什么”和”什么时候做”解耦了。
WindowGroup 的多窗口支持。 在 iPadOS 上,WindowGroup 自动支持创建多个窗口实例。每个窗口有独立的状态(因为 View 是 struct),数据可以通过 @StateObject 或 @EnvironmentObject 在窗口之间共享。系统还自动处理窗口的状态保存和恢复。
代码片段
import SwiftUI
// 最简单的 SwiftUI App——不到 10 行代码
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
// 监听 App 前后台状态变化
struct ContentView: View {
@Environment(\.scenePhase) var scenePhase
var body: some View {
NavigationView {
Text("Hello, World!")
}
.onChange(of: scenePhase) { newPhase in
switch newPhase {
case .active:
print("App 进入前台并活跃")
case .inactive:
print("App 进入前台但不活跃(如来电)")
case .background:
print("App 进入后台")
saveUserData() // 在后台时保存数据
@unknown default:
break
}
}
}
}
// 完整的 App 示例:包含多个 Scene
@main
struct MyApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@StateObject var dataController = DataController()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(dataController)
}
// macOS 上的设置窗口
#if os(macOS)
Settings {
SettingsView()
.environmentObject(dataController)
}
#endif
}
}
// 如果需要处理推送通知等,仍然可以桥接 AppDelegate
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 配置推送通知等
return true
}
}
最佳实践
- 新项目直接用 SwiftUI App 协议。 不需要 AppDelegate 除非你有推送通知、URL Scheme 等必须用 AppDelegate 处理的需求。
- 用
@StateObject创建全局数据管理器。 在 App 级别创建的@StateObject可以通过.environmentObject传递给所有子视图。 scenePhase替代 AppDelegate 的前后台回调。 逻辑更清晰,且可以在任何 View 中使用。- macOS 项目用
SettingsScene。 不需要手动创建设置窗口,SwiftUI 自动管理。
还有什么值得关注
DocumentGroup可以用来创建文档类 App(如编辑器),自动处理文件打开/保存WindowGroup的id参数可以区分不同类型的窗口- SwiftUI App 的生命周期在 watchOS 和 tvOS 上有略微不同的行为
@UIApplicationDelegateAdaptor支持ObservableObject,可以与 SwiftUI 数据流结合