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

Swift中为本地JSON添加checked字段留存勾选状态的技术问询

解决方案:为API数据添加勾选状态并持久化保留

针对你的问题,我分两部分来解决:一是给从API解析的Items添加勾选状态字段,二是在每周更新JSON后保留用户的勾选状态。

1. 为Items添加checked字段(兼容API解析)

你不需要修改API返回的JSON,只需要调整本地的Codable结构体,新增checked属性并让解析器忽略它即可。同时建议遵循Swift的命名规范(小驼峰命名):

struct Base : Codable { 
    let expireDate: String 
    let week: [Week] // 原"Week"映射为小写week
    
    enum CodingKeys: String, CodingKey {
        case expireDate
        case week = "Week"
    }
} 

struct Week : Codable { 
    let name: String 
    let items: [Item] // 原"Items"改为Item,更符合单例命名
} 

struct Item : Codable { 
    let icon: String 
    let text: String 
    var checked: Bool = false // 新增勾选状态,默认未勾选

    enum CodingKeys: String, CodingKey {
        case icon = "Icon" // 映射API的"Icon"字段
        case text
        // 不包含checked,解析API JSON时会自动忽略这个字段
    }
}

这样修改后,解析API返回的JSON时不会报错,因为CodingKeys里没有包含checked,而checked有默认值false,完美兼容原有逻辑。

2. 持久化保留勾选状态(避免被新JSON覆盖)

因为每周会下载新的JSON并覆盖本地存储,所以不能把checked状态存在同一个JSON文件里。我们需要单独用UserDefaults存储每个Item的勾选状态,用Week名称 + Item文本作为唯一标识(如果你的Item有唯一ID,用ID会更可靠,这里假设text是唯一的)。

步骤1:添加状态存储/读取工具方法

// 存储单个Item的勾选状态
private func saveItemCheckedState(weekName: String, itemText: String, isChecked: Bool) {
    let defaults = UserDefaults.standard
    let uniqueKey = "\(weekName)-\(itemText)"
    defaults.set(isChecked, forKey: uniqueKey)
}

// 读取单个Item的勾选状态(默认返回false)
private func getItemCheckedState(weekName: String, itemText: String) -> Bool {
    let defaults = UserDefaults.standard
    let uniqueKey = "\(weekName)-\(itemText)"
    return defaults.bool(forKey: uniqueKey)
}

步骤2:加载数据时恢复勾选状态

不管是从API下载新数据,还是从本地读取旧数据,都需要遍历所有Item,恢复之前存储的勾选状态:

private func restoreCheckedStates(for base: Base) -> Base {
    var mutableBase = base
    // 遍历每个Week
    for weekIndex in mutableBase.week.indices {
        var mutableWeek = mutableBase.week[weekIndex]
        // 遍历Week下的每个Item
        for itemIndex in mutableWeek.items.indices {
            let item = mutableWeek.items[itemIndex]
            let isChecked = getItemCheckedState(weekName: mutableWeek.name, itemText: item.text)
            mutableWeek.items[itemIndex].checked = isChecked
        }
        mutableBase.week[weekIndex] = mutableWeek
    }
    return mutableBase
}

然后在你的数据加载逻辑中调用这个方法:

func loadJson() {
    getItems(for: 1) { [weak self] result in
        guard let self = self else { return }
        switch result {
        case .success(let rawItem):
            // 恢复勾选状态
            let itemWithCheckedStates = self.restoreCheckedStates(for: rawItem)
            self.saveItemsToDisk(items: itemWithCheckedStates)
            self.defaults.set(rawItem.expireDate, forKey: "LastUpdateItems")
            self.itemsDisk = itemWithCheckedStates
        case .failure(let error):
            fatalError("error: \(error.localizedDescription)")
        }
        // 本地加载后也需要恢复状态
        if var localItems = self.itemsDisk {
            localItems = self.restoreCheckedStates(for: localItems)
            self.itemsDisk = localItems
        }
    }
}

步骤3:用户勾选/取消时更新存储

在子TableView的点击事件中,切换Item的checked状态并同步存储:

// 假设这是子TableView的didSelectRowAt方法
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    guard let currentWeek = currentWeek, var items = currentWeek.items else { return }
    // 切换勾选状态
    items[indexPath.row].checked.toggle()
    // 更新数据源
    currentWeek.items = items
    // 存储新状态到UserDefaults
    let item = items[indexPath.row]
    saveItemCheckedState(weekName: currentWeek.name, itemText: item.text, isChecked: item.checked)
    // 刷新当前cell
    tableView.reloadRows(at: [indexPath], with: .automatic)
}

为什么这样做?

  • 单独存储勾选状态到UserDefaults,不会被每周更新的JSON覆盖,确保用户的选择不会丢失。
  • 新增的Item默认checked为false,符合用户预期,且不会影响原有已勾选的Item。
  • 结构体的修改完全兼容原有的API解析逻辑,不需要改动JSON下载和解析的核心代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:59:19