You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI架构:值类型与引用类型及@State/@ObservedObject对比

SwiftUI中@State(值类型)与@ObservedObject(引用类型)的架构选择问题

暂不考虑值类型与引用类型本身的选择理由,仅从SwiftUI架构层面出发,探讨其更偏好使用@State还是@ObservedObject?

以下是一个基础列表应用的两种实现方案:猫采用struct(值类型)实现,狗采用class(引用类型)实现:

import SwiftUI

struct Cat: Identifiable {
    let id = UUID()
    var name: String = "New cat"
}

final class Dog: Identifiable, ObservableObject {
    let id = UUID()
    @Published var name: String = "New dog"
}

final class Dogs: ObservableObject {
    @Published var dogs: [Dog] = []
}

struct ContentView: View {
    @State private var cats: [Cat] = []
    @ObservedObject private var dogs = Dogs()
    
    var body: some View {
        VStack {
            Text("Cats").bold()
            ForEach($cats, content: CatView.init)
            Button("New cat") {
                cats.append(Cat())
            }
            Divider().padding()
            Text("Dogs").bold()
            ForEach(dogs.dogs, content: DogView.init)
            Button("New dog") {
                dogs.dogs.append(Dog())
            }
        }
    }
}

struct CatView: View {
    @Binding var cat: Cat
    
    var body: some View {
        TextField("Name", text: $cat.name)
    }
}

struct DogView: View {
    @ObservedObject var dog: Dog
    
    var body: some View {
        TextField("Name", text: $dog.name)
    }
}

两种实现的代码差异极小,针对以下问题逐一解答:


1. 是否存在偏好其中一种方案的理由?苹果官方示例常采用struct + @State + @Bindings组合。

苹果官方确实更偏好struct + @State + @Binding的组合,核心原因贴合SwiftUI的设计哲学:

  • SwiftUI视图本身是值类型,值类型数据模型能让状态流转更可预测——值类型的复制修改特性,让每一次状态变化都生成新实例,SwiftUI可精准捕捉变化并触发视图更新,避免引用类型可能出现的状态模糊问题。
  • 这种组合代码更简洁,无需额外定义ObservableObject子类和@Published属性,减少样板代码。
  • 架构一致性更强,值类型模型与SwiftUI视图体系天然适配,无需关注ObservedObject的生命周期管理,降低内存泄漏或异常更新的风险。

2. 两种选择是否存在性能差异?比如当Cat或Dog对象包含大量字段(ObservedObject可精确指定触发objectWillChange调用的属性),或者数组包含数十万个元素时。

存在明确的性能差异,分场景来看:

  • 单对象多字段场景:若模型包含大量字段,ObservedObject通过@Published可精准控制触发视图更新的属性;而值类型的@State/@Binding只要模型任意字段修改,就会生成新实例,SwiftUI需对比新旧实例差异决定是否更新——虽SwiftUI的差异对比优化出色,但极端场景(如上百个字段频繁修改)下,引用类型的精准更新效率更高。
  • 大数据数组场景:当数组包含数十万个元素时,值类型数组的单个元素修改会触发数组写时复制(仅修改元素复制,但数组引用变化),@State会触发父视图更新,进而让ForEach重新计算所有子视图差异;而引用类型数组中,单个Dog对象的属性修改仅会让对应DogView更新,父视图不会因数组本身无变化而刷新,性能优势明显。但数组增删操作时,两者性能差异不大,都会触发数组变化通知。

3. 既然Bindings可为值类型赋予伪引用特性,那么何时应选择使用引用类型?

即便@Binding能让值类型拥有类引用的修改能力,以下场景仍更适合引用类型:

  • 跨多视图共享同一状态实例:多个不相关视图需修改同一份数据,且不想通过层层传递Binding实现——引用类型的ObservableObject可作为全局或环境对象,直接在多视图中访问修改,避免Binding链过长带来的代码复杂度。
  • 模型需持有可变引用类型资源:比如模型要管理网络请求任务、Core Data上下文、定时器等引用类型对象,值类型复制后会生成新引用,无法维持对原资源的持有,此时必须用引用类型模型。
  • 复杂状态的精细化更新控制:当模型状态变化逻辑复杂,需精准控制视图更新时机(如部分属性变化无需通知视图),ObservableObject可手动调用objectWillChange.send()控制更新,比値类型的自动更新更灵活。
  • 与现有引用类型API交互:若项目需与UIKit、Core Data等基于引用类型的框架深度集成,使用引用类型模型能减少适配成本。

内容的提问来源于stack exchange,提问作者Philip Pegden

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 03:20:24