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

Swift中重启App后如何维护递增ID计数器的连续值?

解决Swift结构体实例重启后递增ID不接续的问题

你当前用静态序列生成ID的方式只在App运行时有效,因为序列是内存中的临时状态,App重启后会完全重置。要实现跨启动的连续ID,核心是持久化记录最后使用的ID,同时要和已保存的交易数据做同步(避免意外情况导致持久化ID和实际交易最大ID不一致)。

最佳实践方案

既然你的Transactions类已经负责交易数据的加载和保存,把ID的管理逻辑放在这里是最合理的——既可以利用已加载的交易数据校验ID合法性,又能统一处理持久化逻辑。

实现步骤

  1. 用UserDefaults存储最后使用的Buy/Sell交易ID(这类轻量配置数据用UserDefaults足够,无需额外文件)
  2. 初始化Transactions时,先加载已保存的交易,再对比UserDefaults中存储的ID和交易列表中的最大ID,取较大值作为下一个ID的起始值
  3. 提供专门的ID生成方法,每次生成后立即更新UserDefaults
  4. 修改交易结构体的初始化逻辑,改为外部传入ID,去掉结构体内部的序列依赖

修改后的完整代码

1. 更新Transactions类

class Transactions: ObservableObject {
    @Published var buyTransactions = [BuyTransaction]() {
        didSet {
            writeFile()
        }
    }
    
    @Published var sellTransactions = [SellTransaction]() {
        didSet {
            writeFile()
        }
    }
    
    // 用于持久化ID的UserDefaults键
    private let lastBuyIDKey = "LastBuyTransactionID"
    private let lastSellIDKey = "LastSellTransactionID"
    
    // 存储下一个要使用的ID
    private var nextBuyID: Int
    private var nextSellID: Int
    
    init() {
        // 先加载已保存的交易数据
        readFile()
        
        // 从UserDefaults读取上次保存的ID,默认值为0
        let savedLastBuyID = UserDefaults.standard.integer(forKey: lastBuyIDKey)
        let savedLastSellID = UserDefaults.standard.integer(forKey: lastSellIDKey)
        
        // 取已存在交易的最大ID和持久化ID的较大值,加1作为下一个ID的起始
        let maxExistingBuyID = buyTransactions.map { $0.id }.max() ?? 0
        nextBuyID = max(savedLastBuyID, maxExistingBuyID) + 1
        
        let maxExistingSellID = sellTransactions.map { $0.id }.max() ?? 0
        nextSellID = max(savedLastSellID, maxExistingSellID) + 1
    }
    
    // 生成新的Buy交易ID并持久化
    func generateNextBuyID() -> Int {
        let id = nextBuyID
        nextBuyID += 1
        UserDefaults.standard.set(nextBuyID - 1, forKey: lastBuyIDKey)
        return id
    }
    
    // 生成新的Sell交易ID并持久化
    func generateNextSellID() -> Int {
        let id = nextSellID
        nextSellID += 1
        UserDefaults.standard.set(nextSellID - 1, forKey: lastSellIDKey)
        return id
    }
    
    // 保留你原有的文件读写逻辑
    private func readFile() {
        // 原有逻辑:从文件加载buyTransactions和sellTransactions
    }
    
    private func writeFile() {
        // 原有逻辑:将buyTransactions和sellTransactions写入文件
    }
}

2. 简化交易结构体

struct BuyTransaction: Identifiable, Codable {
    let id: Int
    let dateTime: Date
    let someOtherValue: String
    
    // 改为接受外部传入的ID,去掉内部的序列依赖
    init(
        id: Int,
        dateTime: Date,
        someOtherValue: String
    ) {
        self.id = id
        self.dateTime = dateTime
        self.someOtherValue = someOtherValue
    }
}

struct SellTransaction: Identifiable, Codable {
    let id: Int
    let dateTime: Date
    let someOtherValue: String
    let andMoreValues: String
    
    init(
        id: Int,
        dateTime: Date,
        someOtherValue: String,
        andMoreValues: String
    ) {
        self.id = id
        self.dateTime = dateTime
        self.someOtherValue = someOtherValue
        self.andMoreValues = andMoreValues
    }
}

3. 使用示例

创建新交易时,通过Transactions实例生成ID:

// 假设你已经初始化了Transactions实例
let transactions = Transactions()

// 创建新的买入交易
let newBuyTx = BuyTransaction(
    id: transactions.generateNextBuyID(),
    dateTime: Date(),
    someOtherValue: "测试买入"
)
transactions.buyTransactions.append(newBuyTx)

// 创建新的卖出交易
let newSellTx = SellTransaction(
    id: transactions.generateNextSellID(),
    dateTime: Date(),
    someOtherValue: "测试卖出",
    andMoreValues: "附加数据"
)
transactions.sellTransactions.append(newSellTx)

方案优势

  • 统一管理:ID生成逻辑集中在Transactions类,避免多个结构体各自维护状态
  • 数据安全:同时校验持久化ID和已保存交易的最大ID,防止App崩溃等意外情况导致的ID重复
  • 轻量高效:用UserDefaults存储ID,无需额外文件或数据库操作
  • 职责清晰:交易结构体只负责存储数据,ID由外部管理,符合单一职责原则

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 15:00:41