Swift 掌握 Observation 框架

前言

Apple 推出了由 Swift 语言的宏功能支持的新观察框架。新的观察框架与 Swift 并发功能结合使用,允许我们替代 Apple 公司看起来已经过时的 Combine 框架。下面将介绍如何使用观察框架来处理应用程序中的数据流。

使用 @Observable

RevenueCat 简化了实施应用内购买、管理客户和扩展应用业务的过程。无论你是第一次添加应用内购买和订阅,还是已经有数百万付费用户,你都可以在几分钟内开始使用 RevenueCat。看看为什么有超过 30,000 个应用程序使用 RevenueCat 来支持其应用业务。你可以查看他们的文档以了解更多信息。

使用新的观察框架非常容易。你只需要使用 @Observable 宏标记你的类。

swift 复制代码
@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 常量。

swift 复制代码
withObservationTracking {
    render(store.state)
} onChange: {
    print("State changed")
}

调用闭包

要观察 Store 类型的实例,我们需要使用 withObservationTracking 函数调用两个闭包。在第一个闭包中,我们可以访问可观察类型的所有必要属性。观察框架仅在触摸到的观察类型的任何属性更改后才调用第二个闭包。

swift 复制代码
func startObservation() {
    withObservationTracking {
        render(store.state)
    } onChange: {
        Task { startObservation() }
    }
}

观察框架仅运行一次 onChange,这意味着你应该递归调用它以不断观察更改。你还应该注意的另一件事是 onChange 闭包在实际更改应用之前运行。这就是为什么我们通过启动新任务来推迟 onChange 操作的原因。

SwiftUI 自动跟踪

在 SwiftUI 中,你不需要使用 withObservationTracking 函数来观察更改。SwiftUI 自动跟踪视图正文中使用的任何可观察类型属性的更改。

swift 复制代码
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 属性包装器现在适用于简单的值类型和任何可观察类型。

swift 复制代码
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 属性包装器和具有可观察类型的环境视图修改器。

swift 复制代码
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 属性包装器,只能与可观察类型一起使用。

swift 复制代码
@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 到视图正文中以创建绑定。

swift 复制代码
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 中的数据流管理更加轻松和高效。

相关推荐
humiaor13 小时前
Xcode报错:No exact matches in reference to static method ‘buildExpression‘
swiftui·xcode
营赢盈英2 天前
OpenAI GPT-3 API error: “You must provide a model parameter“
chatgpt·gpt-3·openai·swift
一只不会编程的猫2 天前
高德地图绘图,点标记,并计算中心点
开发语言·ios·swift
loongloongz2 天前
Swift语言基础教程、Swift练手小项目、Swift知识点实例化学习
开发语言·学习·swift
2401_858120536 天前
深入理解 Swift 中的隐式解包可选类型(Implicitly Unwrapped Optionals)
开发语言·ios·swift
quaer6 天前
QT chart案例
开发语言·qt·swift
安和昂7 天前
【iOS】UIViewController的生命周期
ios·xcode·swift
00圈圈7 天前
Swift 创建扩展(Extension)
ios·swift·extension
2401_858120537 天前
Swift 中的函数:定义、使用与实践指南
开发语言·ssh·swift
quaer8 天前
VS+QT--实现二进制和十进制的转换(含分数部分)
java·开发语言·python·qt·swift