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

SwiftUI中如何为Post模型创建随数据更新的commentIds变量?

问题描述

我有如下格式的JSON数据:

{
  "id": 1,
  "comments": [
    {"id": 1, "message": "Hello"},
    {"id": 2, "message": "There"},
    {"id": 3, "message": "World"}
  ]
}

针对该JSON,我定义了Post和Comment模型:

struct Post: Codable, Identifiable {
    let id: Int
    let comments: [Comment]

    enum CodingKeys: String, CodingKey {
        case id = "id"
        case comments = "comments"
    }
}

struct Comment: Codable, Identifiable {
    let id: Int
    let message: String

    enum CodingKeys: String, CodingKey {
        case id = "id"
        case message = "message"
    }
}

在SwiftUI中,我使用EnvironmentObject确保数据变化时视图自动更新,这一功能运行正常。但我希望在Post模型中新增一个变量commentIds,用于存储所有Comment的id数组(示例中应为[1, 2, 3])。已知计算属性无法在SwiftUI数据更新时自动触发视图更新,请问如何创建可随Post数据更新且同步更新视图的自定义变量?

解决方案

提供两种适配SwiftUI响应式更新的实现方式,可根据模型使用场景选择:

方式一:将Post改为ObservableObject(推荐用于频繁修改的场景)

把Post从struct改为遵循ObservableObject的class,用@Published标记comments属性,同时把commentIds作为存储属性,在comments的didSet回调中同步更新。这样当comments变化时,既会触发SwiftUI视图更新,也能保证commentIds始终与comments的id数组一致:

class Post: ObservableObject, Codable, Identifiable {
    let id: Int
    @Published var comments: [Comment] {
        didSet {
            commentIds = comments.map { $0.id }
        }
    }
    var commentIds: [Int]
    
    // 手动实现Codable解码逻辑,初始化时同步生成commentIds
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self, forKey: .id)
        comments = try container.decode([Comment].self, forKey: .comments)
        commentIds = comments.map { $0.id }
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(comments, forKey: .comments)
    }
    
    enum CodingKeys: String, CodingKey {
        case id, comments
    }
    
    // 自定义初始化方法,用于手动创建Post实例
    init(id: Int, comments: [Comment]) {
        self.id = id
        self.comments = comments
        self.commentIds = comments.map { $0.id }
    }
}

struct Comment: Codable, Identifiable {
    let id: Int
    let message: String
}

使用时,将Post实例包装为@StateObject或注入为EnvironmentObject,当comments修改时,commentIds会自动更新并触发视图刷新。

方式二:保持Post为struct(适用于数据修改较少的场景)

如果希望保留Post值类型的特性,可将commentIds设为存储属性,在初始化(包括解码)时赋值,并提供一个mutating方法来同步修改comments和commentIds:

struct Post: Codable, Identifiable {
    let id: Int
    var comments: [Comment]
    var commentIds: [Int]
    
    enum CodingKeys: String, CodingKey {
        case id, comments
    }
    
    // 解码时自动生成commentIds
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self, forKey: .id)
        comments = try container.decode([Comment].self, forKey: .comments)
        commentIds = comments.map { $0.id }
    }
    
    // 自定义初始化方法
    init(id: Int, comments: [Comment]) {
        self.id = id
        self.comments = comments
        self.commentIds = comments.map { $0.id }
    }
    
    // 同步更新comments和commentIds的方法
    mutating func updateComments(_ newComments: [Comment]) {
        comments = newComments
        commentIds = newComments.map { $0.id }
    }
}

struct Comment: Codable, Identifiable {
    let id: Int
    let message: String
}

这种方式下,必须通过调用updateComments方法修改comments,不能直接给comments赋值,才能保证commentIds同步更新。当Post实例作为@State或包装在ObservableObject(如@Published var post: Post)中注入为EnvironmentObject时,修改后会触发视图更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 14:47:08