用 @Observable 重构你的 SwiftUI:新手也能轻松上手的状态管理方案

在这里插入图片描述

网罗开发 (小红书、快手、视频号同名)

  大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。

图书作者:《ESP32-C3 物联网工程开发实战》
图书作者:《SwiftUI 入门,进阶与实战》
超级个体:COC上海社区主理人
特约讲师:大学讲师,谷歌亚马逊分享嘉宾
科技博主:华为HDE/HDG

我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。

展菲:您的前沿技术领航员
👋 大家好,我是展菲!
📱 全网搜索“展菲”,即可纵览我在各大平台的知识足迹。
📣 公众号“Swift社区”,每周定时推送干货满满的技术长文,从新兴框架的剖析到运维实战的复盘,助您技术进阶之路畅通无阻。
💬 微信端添加好友“fzhanfei”,与我直接交流,不管是项目瓶颈的求助,还是行业趋势的探讨,随时畅所欲言。
📅 最新动态:2025 年 3 月 17 日
快来加入技术社区,一起挖掘技术的无限潜能,携手迈向数字化新征程!


前言

Apple 最近推出了一个新观察框架,是基于 Swift 的宏功能做的。它可以和 Swift 的并发特性结合起来用,而且看上去是要逐步替代以前的 Combine 框架了。这次我们就来聊聊这个观察框架的用法,以及它在项目中能帮我们解决什么问题。

痛点分析

在用 SwiftUI 做开发的时候,很多人都碰到过这几个问题:

  1. 数据流太复杂:不同 View 之间传值、绑定、通知很麻烦。

  2. 生命周期混乱:比如 @ObservedObject@StateObject@EnvironmentObject 到底该用哪个,新手特别容易踩坑。

  3. Combine 学习曲线陡峭:虽然功能强,但很多时候只是为了监听某个状态变化,结果搞得又重又绕。

  4. 性能和资源占用:老框架有时候更新太频繁,带来额外的性能开销。

实际场景举例

假设我们有一个电商 app,有商品列表、详情页、购物车、用户登录等模块。以前我们可能得手动管理各种状态、绑定和事件通知,逻辑分散在不同 View 和 ViewModel 中,调试也不方便。

现在有了新的观察框架,这些模块之间可以共享统一的状态,比如商品数据、用户信息,而且更新时视图会自动响应。加上新的属性包装器像 @Observable@Bindable,写法更清晰,维护也轻松。

使用 @Observable

直接上例子,先创建一个简单的 Store 类,用来管理状态和派发动作:

@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)
    }
}

观察状态变化

通过 withObservationTracking 这个方法,我们可以观察状态的变化,然后触发 UI 更新或者其他操作。

withObservationTracking {
    render(store.state)
} onChange: {
    print("State changed")
}

这个回调只会在 store.state 真正发生变化时触发。

实现持续观察

我们可以递归地调用这个监听方法,实现持续观察。

func startObservation() {
    withObservationTracking {
        render(store.state)
    } onChange: {
        Task { startObservation() }
    }
}

注意:这个 onChange 是在状态变化“之前”触发的,所以我们用 Task 包一层,让它异步执行。

SwiftUI 中的自动监听

如果你在 SwiftUI 里用这些新特性,基本不需要手动写监听逻辑了。它会自动追踪 View 中访问到的可观察属性。

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)
        }
    }
}

用 @State 管状态

新的框架下,@State 属性包装器变得更强了,它可以直接处理可观察对象,不再局限于值类型。

struct ContentView: View {
    @State private var store = Store<AppState, AppAction>(
        initialState: .init(),
        reduce: reduce
    )

    var body: some View {
        ProductsView(store: store)
    }
}

用 @Environment 共享数据

以前我们用 @EnvironmentObject,现在可以直接用 @Environment 搭配 .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 做双向绑定

如果你想从可观察对象中直接创建绑定,比如表单输入,那就用 @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)")
            }
        }
    }
}

QA 环节

Q: Combine 还能用吗?要不要全部替换?
A: 目前还是能用的,但如果你在做新项目,建议尝试用观察框架,结构更清晰,而且跟 SwiftUI 搭配很好。

Q: 会不会影响性能?
A: 不会乱监听,它只追踪你访问过的属性,而且只有在状态真正变化时才触发更新。

Q: 多层嵌套的 View 怎么共享状态?
A: 用 @Environment.environment(...) 组合传递,清晰又方便。

总结

这个新观察框架简化了我们在 SwiftUI 里处理状态和更新的方式,不需要额外引入 Combine,也不再纠结各种属性包装器的选择。实际项目中,比如商品列表、用户登录、状态管理这些场景都可以用得上。

未来展望

  • 后面可能会有更多结合宏和并发的语法糖,开发体验会继续优化。

  • 官方文档还在持续更新,建议持续关注 Swift 和 SwiftUI 的新特性。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

网罗开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值