如何对比两个含自定义Swift对象的数组并按ID去重添加?
解决数组对比与UserDefaults存储问题
你的核心需求其实分为两部分:将API返回的新数据合并到本地数组中,以及把最终数组持久化到UserDefaults。先从你的数组对比逻辑说起,再补充UserDefaults的实现细节。
一、数组对比逻辑的优化与验证
你写的contains(where:)逻辑本身是正确的,但可能因为两个原因导致没达到预期:
lenders数组初始为空,没有从UserDefaults读取已有数据,导致每次都直接添加所有temp对象;LenderData的id类型不匹配(比如一个是String一个是Int),或者id的取值有问题。
先给你优化后的合并逻辑,用Set来提升查找效率(尤其是数组元素较多时):
private func mergeNewLenders() { // 先把已有lenders的id存入Set,O(1)查找效率 let existingLenderIds = Set(lenders.map { $0.id }) // 过滤出temp中不存在于已有数组的对象 let newLenders = lendersTemp.filter { !existingLenderIds.contains($0.id) } // 批量添加新对象 lenders.append(contentsOf: newLenders) }
如果你的数组元素不多,原来的循环写法也完全可以用,核心是确保$0.id == tempLender.id的对比是有效的。
二、UserDefaults存储的完整实现
要把自定义类型LenderData存入UserDefaults,必须让它遵循Codable协议(这是Swift中序列化/反序列化自定义对象的标准方式):
1. 修改LenderData结构
struct LenderData: Codable { let id: String // 或者Int,根据你的API返回类型调整 // 这里添加你的其他属性,比如name、address等 }
2. 实现UserDefaults的读写方法
在你的ViewController中添加两个私有方法,负责读取和存储数组:
private func loadLendersFromUserDefaults() { guard let savedData = UserDefaults.standard.data(forKey: "SavedLenders") else { lenders = [] return } do { // 反序列化数据为LenderData数组 lenders = try JSONDecoder().decode([LenderData].self, from: savedData) } catch { print("读取本地数据失败: \(error.localizedDescription)") lenders = [] } } private func saveLendersToUserDefaults() { do { // 序列化数组为Data类型 let dataToSave = try JSONEncoder().encode(lenders) UserDefaults.standard.set(dataToSave, forKey: "SavedLenders") // iOS 10+后自动同步,这里加上更保险 UserDefaults.standard.synchronize() } catch { print("保存数据到本地失败: \(error.localizedDescription)") } }
3. 在viewDidLoad中整合流程
调整你的viewDidLoad,把读取、下载、合并、存储的流程串起来:
var lenders = [LenderData]() var lendersTemp = [LenderData]() override func viewDidLoad() { super.viewDidLoad() // 第一步:先从UserDefaults读取已存储的本地数据 loadLendersFromUserDefaults() // 第二步:下载API数据,完成后合并并存储 downloadJSON { self.mergeNewLenders() self.saveLendersToUserDefaults() self.myTableView.reloadData() } self.myTableView.rowHeight = 90 myTableView.delegate = self myTableView.dataSource = self }
三、常见问题排查
如果还是没达到预期,可以检查这几点:
- 确认
LenderData的所有属性都符合Codable要求(比如没有自定义的非Codable类型); - 打印
tempLender.id和已有lenders中对象的id,确认对比逻辑正确; - 在
saveLendersToUserDefaults后,打印UserDefaults.standard.data(forKey: "SavedLenders"),确认数据确实被存储。
内容的提问来源于stack exchange,提问作者IncrediblePony
相关产品推荐
相关产品推荐

