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

SwiftUI List为何首次HTTP请求后无法正确更新User对象

问题分析

你的问题根源有两个:

  1. @State 不适用于引用类型:User 是类(引用类型),而 @State 是为值类型设计的属性包装器。用它存储引用类型时,SwiftUI 无法正确追踪实例内部的属性变化,且当父视图的 List 重新渲染时,会将原 users 数组中的实例重新传入 ReviewView,覆盖你更新后的实例。
  2. 直接替换实例而非更新属性:updateCount 中直接将 userVar 替换为服务器返回的新 User 实例,原 users 数组中的实例并未被修改。当视图刷新时,ReviewView 又会拿到旧的实例,导致无法持续更新。
解决方案

步骤1:让 User 类支持属性变化监听

修改 User 类,遵循 ObservableObject 协议,并将需要监听的 countReviews 属性用 @Published 标记,这样 SwiftUI 能感知到属性变化并刷新视图:

class User: Codable, Identifiable, ObservableObject {
    let id: Int
    @Published var countReviews: Int?
}

步骤2:修改 ReviewView 的属性包装器

将 @State 替换为 @ObservedObject,用于监听引用类型的属性变化:

struct ReviewView: View {
    @ObservedObject var userVar: User
    
    var body: some View {
        Text(userVar.countReviews?.description ?? "0")
            .task {
                await updateCount()
            }
    }

    func updateCount() async {
        // HTTP 请求获取服务器返回的 User 对象
        guard let responseUser = await fetchUpdatedUser(userId: userVar.id) else {
            return
        }
        // 不替换整个实例,仅更新现有实例的属性
        userVar.countReviews = responseUser.countReviews
    }
    
    // 实际项目中替换为真实的网络请求逻辑
    private func fetchUpdatedUser(userId: Int) async -> User? {
        // 模拟服务器返回数据
        return User(id: userId, countReviews: Int.random(in: 1...100))
    }
}

步骤3:父视图保持原有结构

父视图的 List 和 ForEach 无需修改,因为现在 User 是 ObservableObject,ReviewView 能自动监听其属性变化:

// 父视图示例代码
var users: [User] = [User(id: 1, countReviews: nil), User(id: 2, countReviews: nil)]

var body: some View {
    List {
        ForEach(users) { user in
            ReviewView(userVar: user)
        }
    }
}
关键说明
  • 使用 @ObservedObject 监听 User 实例的属性变化,确保属性更新时视图自动刷新。
  • 更新现有实例的属性而非替换整个实例,这样原 users 数组中的实例会同步更新,避免视图刷新时回到旧数据。
  • 给 countReviews 添加空值处理(比如 ?? "0"),避免可选值为 nil 时崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 12:27:47