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

Swift+Cocoa文件下载器:如何在不清除旧数据的情况下更新Plist下载历史

解决Plist写入覆盖原有下载历史的问题

嘿,这个问题很常见——你现在的代码每次都是直接创建一个全新的downloadList对象写入文件,自然会把旧数据完全覆盖掉。要保留历史数据,正确的思路是先读取已有的下载记录,把新条目添加进去,再整体写入文件。我来帮你一步步修改代码:

第一步:修改Codable结构体的可变性

首先你的downloadList结构体里的root是let常量,没法修改数组内容。得把它改成var变量,允许我们添加新条目:

public struct downloadList: Codable {
    var root: [downloadListt] // 将let改为var,支持数组修改
}
public struct downloadListt: Codable {
    let downloadURL: String
    let fileName: String
}

第二步:添加读取已有下载历史的方法

写一个专门的方法加载本地已有的Plist数据,同时处理文件不存在(第一次写入场景)或者读取失败的情况:

func loadExistingDownloads() -> downloadList {
    guard let pListFileURL = uniqueDataDir()?.appendingPathComponent("downloads.plist") else {
        return downloadList(root: [])
    }
    
    // 如果文件还没创建过,直接返回空的下载列表
    guard FileManager.default.fileExists(atPath: pListFileURL.path) else {
        return downloadList(root: [])
    }
    
    do {
        let data = try Data(contentsOf: pListFileURL)
        let decoder = PropertyListDecoder()
        return try decoder.decode(downloadList.self, from: data)
    } catch {
        print("读取下载历史失败:\(error)")
        // 读取出错时也返回空数组,避免程序崩溃
        return downloadList(root: [])
    }
}

第三步:修改写入逻辑,合并新旧数据

把原来的“直接写入新数据”改成“读取旧数据→添加新条目→写回文件”的流程,同时优化可选值处理避免崩溃:

// 先安全处理可选值,不要用强制解包
guard let downloadURL = response.url?.absoluteString,
      let fileName = response.suggestedFilename else {
    print("无法获取下载URL或文件名")
    return
}

// 1. 创建新的下载条目
let newItem = downloadListt(downloadURL: downloadURL, fileName: fileName)

// 2. 加载已有的下载历史
var existingDownloads = loadExistingDownloads()

// 3. 将新条目添加到历史数组中
existingDownloads.root.append(newItem)

// 4. 编码并写入文件
let encoder = PropertyListEncoder()
encoder.outputFormat = .xml
guard let pListFileURL = uniqueDataDir()?.appendingPathComponent("downloads.plist") else {
    return
}

do {
    let data = try encoder.encode(existingDownloads)
    try data.write(to: pListFileURL)
    print("下载历史更新成功")
} catch {
    print("写入下载历史失败:\(error)")
}

额外的优化建议

  • 线程安全:如果你的下载操作在后台线程执行,建议把Plist读写放到串行队列里处理,避免并发读写导致的数据损坏。
  • 数据去重:如果不想重复存储同一个下载条目,可以在添加新条目前检查existingDownloads.root里是否已有相同downloadURL的记录,避免冗余数据。
  • 目录创建:确保uniqueDataDir()返回的目录已经存在,可以用FileManager.default.createDirectory(at:withIntermediateDirectories:attributes:)提前创建目录。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 11:24:16