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

如何编写低样板代码的Swift GRDB模型(支持自动更新与JSON加载)

优化GRDB模型,减少样板代码

针对你遇到的每个字段重复多次的问题,可以通过以下几个方向简化代码:

1. 利用Swift自动合成Codable实现

只要你的CodingKeys枚举(如果需要自定义键名)或属性名称与JSON键名完全匹配,Swift会自动为你生成init(from:)和encode(to:)方法,无需手动编写。

2. 利用GRDB的自动合成能力

GRDB支持自动合成FetchableRecord和PersistableRecord的核心方法,只要Columns枚举的case名称和属性名一致,就不用手动实现init(row:)和encode(to:inout PersistenceContainer)。

3. 用属性包装器复用自动保存逻辑

把@Published的didSet自动保存逻辑封装成属性包装器,避免每个字段都重复写didSet { save() }。

优化后的完整代码

import Foundation
import GRDB

// 自定义属性包装器,封装@Published与自动保存逻辑
@propertyWrapper
struct AutoSavePublished<Value> {
    @Published var wrappedValue: Value
    private let saveAction: () -> Void
    
    init(wrappedValue: Value, saveAction: @escaping () -> Void) {
        self.wrappedValue = wrappedValue
        self.saveAction = saveAction
    }
    
    // 保留@Published的投影值用法(如$name)
    var projectedValue: Published<Value>.Publisher {
        $wrappedValue
    }
    
    mutating func setValue(_ value: Value) {
        wrappedValue = value
        saveAction()
    }
}

class Routine: Identifiable, Codable, FetchableRecord, PersistableRecord, ObservableObject {
    var id: UUID = UUID()
    @AutoSavePublished var name: String
    
    // GRDB表名定义
    static let databaseTableName = "routines"
    
    // 类型安全列枚举,与属性名一致即可
    enum Columns: String, ColumnExpression {
        case id, name
    }
    
    // 自定义初始化器
    init(id: UUID, name: String) {
        self.id = id
        self._name = AutoSavePublished(wrappedValue: name, saveAction: self.save)
    }
    
    // 自动保存方法
    func save() {
        do {
            try DatabaseManager.shared.dbQueue.write { db in
                try self.save(db)
            }
        } catch {
            print("Error saving routine:", error)
        }
    }
}

关键优化点说明

  • Codable简化:删除了手动编写的CodingKeys、init(from:)和encode(to:),Swift会根据属性名自动生成这些代码;如果需要自定义JSON键名,仅需添加CodingKeys枚举即可,无需手动实现编码解码逻辑。
  • GRDB方法自动合成:GRDB会检测到Columns枚举的case与属性名匹配,自动为你实现数据库行的读取和写入逻辑,无需手动编写字段映射。
  • 属性包装器复用逻辑:AutoSavePublished包装器把@Published和自动保存的逻辑封装在一起,新增字段时只需要用@AutoSavePublished修饰,不用再重复写didSet代码。

自定义JSON键名的情况

如果你的模型字段需要自定义JSON键名,仅需添加CodingKeys枚举,Swift依然会自动合成编码解码方法:

extension Routine {
    enum CodingKeys: String, CodingKey {
        case id
        case name = "routine_display_name" // 自定义JSON键名
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 00:16:06