前言
Apple 推出了由 Swift 语言的宏功能支持的新观察框架。新的观察框架与 Swift 并发功能结合使用,允许我们替代 Apple 公司看起来已经过时的 Combine 框架。下面将介绍如何使用观察框架来处理应用程序中的数据流。
使用 @Observable
RevenueCat 简化了实施应用内购买、管理客户和扩展应用业务的过程。无论你是第一次添加应用内购买和订阅,还是已经有数百万付费用户,你都可以在几分钟内开始使用 RevenueCat。看看为什么有超过 30,000 个应用程序使用 RevenueCat 来支持其应用业务。你可以查看他们的文档以了解更多信息。
使用新的观察框架非常容易。你只需要使用 @Observable
宏标记你的类。
@Observable final class Store<State, Action> {
typealias Reduce = (State, Action) -> State
private(set) var state: State
private let reduce: Reduce
init(initialState state: State, reduce: @escaping Reduce) {
self.state = state
self.reduce = reduce
}
func send(_ action: Action) {
state = reduce(state, action)
}
}
观察 Store
正如你在上面的示例中所看到的,我们使用 @Observable
宏来注释我们的 Store 类型。之后,我们可以观察 Store 类型中的任何变量。我们在 Store 类型中只有一个变量,用于定义存储的状态。另一个字段是一个永不更改的 let 常量。
withObservationTracking {
render(store.state)
} onChange: {
print("State changed")
}
调用闭包
要观察 Store 类型的实例,我们需要使用 withObservationTracking
函数调用两个闭包。在第一个闭包中,我们可以访问可观察类型的所有必要属性。观察框架仅在触摸到的观察类型的任何属性更改后才调用第二个闭包。
func startObservation() {
withObservationTracking {
render(store.state)
} onChange: {
Task { startObservation() }
}
}
观察框架仅运行一次 onChange
,这意味着你应该递归调用它以不断观察更改。你还应该注意的另一件事是 onChange
闭包在实际更改应用之前运行。这就是为什么我们通过启动新任务来推迟 onChange
操作的原因。
SwiftUI 自动跟踪
在 SwiftUI 中,你不需要使用 withObservationTracking
函数来观察更改。SwiftUI 自动跟踪视图正文中使用的任何可观察类型属性的更改。
struct ProductsView: View {
let store: Store<AppState, AppAction>
var body: some View {
List(store.state.products, id: .self) { product in
Text(product)
}
.onAppear {
store.send(.fetch)
}
}
}
正如你在上面的示例中所看到的,我们不使用任何属性包装器来观察存储。SwiftUI 自动执行此操作。只要存储的状态属性更改,SwiftUI 就会更新视图。我们不需要 @ObservedObject
属性包装器来跟踪可观察类型中的更改,但我们仍然需要 @StateObject
替代项以在 SwiftUI 生命周期中存活。
使用 @State
Apple 简化了我们应该在新的观察框架中使用的属性包装器集。现在,我们可以使用 @State
而不是 @StateObject
属性包装器。@State
属性包装器现在适用于简单的值类型和任何可观察类型。
struct ContentView: View {
@State private var store = Store<AppState, AppAction>(
initialState: .init(),
reduce: reduce
)
var body: some View {
ProductsView(store: store)
}
}
使用 @Environment
相同的方法适用于 SwiftUI 框架的环境功能。现在不再需要 @EnvironmentObject
属性包装器。你现在可以使用 @Environment
属性包装器和具有可观察类型的环境视图修改器。
struct ContentView: View {
@State private var store = Store<AppState, AppAction>(
initialState: .init(),
reduce: reduce
)
var body: some View {
ProductsView()
.environment(store)
}
}
struct ProductsView: View {
@Environment(Store<AppState, AppAction>.self) var store
var body: some View {
List(store.state.products, id: .self) { product in
Text(product)
}
.onAppear {
store.send(.fetch)
}
}
}
使用 @Bindable
你可能会想知道的最后一件事是如何从可观察类型中派生绑定。SwiftUI 为此引入了 @Bindable
属性包装器,只能与可观察类型一起使用。
@Observable final class AuthViewModel {
var username = ""
var password = ""
var isAuthorized = false
func authorize() {
isAuthorized.toggle()
}
}
struct AuthView: View {
@Bindable var viewModel: AuthViewModel
var body: some View {
VStack {
if !viewModel.isAuthorized {
TextField("username", text: $viewModel.username)
SecureField("password", text: $viewModel.password)
Button("authorize") {
viewModel.authorize()
}
} else {
Text("Hello, (viewModel.username)")
}
}
}
}
你可以使用 @Bindable
属性包装器轻松地从任何可观察类型的属性创建绑定。有时,你可能需要内联 @Bindable
到视图正文中以创建绑定。
struct InlineAuthView: View {
@Environment(AuthViewModel.self) var viewModel
var body: some View {
@Bindable var viewModel = viewModel
VStack {
if !viewModel.isAuthorized {
TextField("username", text: $viewModel.username)
SecureField("password", text: $viewModel.password)
Button("authorize") {
viewModel.authorize()
}
} else {
Text("Hello, (viewModel.username)")
}
}
}
}
总结
这篇文章介绍了苹果引入的全新观察框架,该框架利用 Swift 语言的宏功能。新的观察框架结合了 Swift 并发功能,使我们能够替代苹果看似已经过时的 Combine 框架。
总的来说,新的观察框架使 SwiftUI 中的数据流管理更加轻松和高效。