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

SwiftUI中含类数组的@Observable类滑动时内存占用过高问题

问题根源

@Observable类的特性是:当类中任意属性发生变化时,整个对象会被标记为已变更,触发所有依赖该对象的视图重绘。在你的代码中,滑动滑块修改variable时,整个ObserveThis实例都会触发更新,导致展示数组的LazyVGrid部分也随之频繁重绘;加上数组中存储的是类实例,频繁的视图重建会导致内存占用持续攀升。

解决办法

1. 拆分Observable对象,隔离可变属性与静态数组

将需要频繁更新的滑块变量和静态数组拆分到两个独立的@Observable类中,这样当滑块变量变化时,只有依赖它的视图会更新,数组相关视图不受影响:

class Thing: Identifiable {
    let id = UUID()
    var variable: UInt8 = 0
    
    init(variable: UInt8 = 0) {
        self.variable = variable
    }
}

@Observable
class SliderState {
    var variable: Float = 1
}

@Observable
class ThingState {
    var things = [[Thing]](repeating: [Thing](repeating: Thing(), count: 512), count: 8)
}

struct ContentView: View {
    @State private var sliderState = SliderState()
    @State private var thingState = ThingState()
    
    private let flexibleColumn = [
        GridItem(.flexible(minimum: 100, maximum: 200)),
        GridItem(.flexible(minimum: 100, maximum: 200)),
        GridItem(.flexible(minimum: 100, maximum: 200))
    ]
    
    var body: some View {
        VStack {
            Slider(
                value: $sliderState.variable,
                in: 0...100,
                step: 5
            ) {
                Text("Variable")
            }
            Text("\(sliderState.variable)")
            
            ScrollView{
                LazyVGrid(columns: flexibleColumn, spacing: 20) {
                    ForEach(thingState.things[0].prefix(64)) { thing in
                        Text(String(thing.variable))
                            .frame(width: 100, height: 100, alignment: .center)
                            .background(.blue)
                            .cornerRadius(10)
                            .foregroundColor(.white)
                            .font(.title)
                    }
                }
            }
            .padding()
        }
        .padding(20)
    }
}

2. 改用结构体存储数组元素(可选优化)

将Thing从类改为结构体,值类型在SwiftUI视图更新时的内存管理更高效,避免不必要的引用计数开销:

struct Thing: Identifiable {
    let id = UUID()
    var variable: UInt8 = 0
}

3. 手动控制视图依赖范围(进阶)

如果不想拆分Observable对象,可以使用withObservationTracking限定视图只追踪特定属性的变化,避免数组部分被不必要地重绘:

// 在ContentView的ScrollView部分修改为:
ScrollView{
    withObservationTracking {
        LazyVGrid(columns: flexibleColumn, spacing: 20) {
            ForEach(1...64, id: \.self) { index in
                Text(String(observing.things[0][index].variable))
                    .frame(width: 100, height: 100, alignment: .center)
                    .background(.blue)
                    .cornerRadius(10)
                    .foregroundColor(.white)
                    .font(.title)
            }
        }
    } onChange: {
        // 仅在数组内容变化时触发更新
    }
}
.padding()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 06:50:55