关于 axiom-sqlitedata-migration
这是一份面向应用开发者的迁移指南,介绍如何将数据从 SwiftData 迁移到 SQLiteData。内容包括常见 API 对照、CloudKit 记录共享与性能考量,以及保留数据和分阶段迁移的方法。
主要功能
- 01对照 SwiftData 与 SQLiteData 模式
- 02配置 CloudKit 记录共享
- 03比较性能特征
- 04导出并导入现有用户数据
- 05逐步迁移数据模型
- 06处理关系和级联删除
适用场景
- 01将性能瓶颈模型迁移到 SQLiteData
- 02为应用添加记录共享
- 03迁移时保留用户数据
- 04与 SwiftData 并行逐步采用 SQLiteData
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ charleswiltgen/ axiom --skill axiom-sqlitedata-migration安装后在 Claude Code 中输入/axiom-sqlitedata-migration确认已加载。
详细介绍
从 SwiftData 迁移到 SQLiteData
何时切换
┌─────────────────────────────────────────────────────────┐
│ Should I switch from SwiftData to SQLiteData? │
├─────────────────────────────────────────────────────────┤
│ │
│ Performance problems with 10k+ records? │
│ YES → SQLiteData (10-50x faster for large datasets) │
│ │
│ Need CloudKit record SHARING (not just sync)? │
│ YES → SQLiteData (SwiftData cannot share records) │
│ │
│ Complex queries across multiple tables? │
│ YES → SQLiteData + raw GRDB when needed │
│ │
│ Need Sendable models for Swift 6 concurrency? │
│ YES → SQLiteData (value types, not classes) │
│ │
│ Testing @Model classes is painful? │
│ YES → SQLiteData (pure structs, easy to mock) │
│ │
│ Happy with SwiftData for simple CRUD? │
│ YES → Stay with SwiftData (simpler for basic apps) │
│ │
└─────────────────────────────────────────────────────────┘
模式对应关系
| SwiftData | SQLiteData |
|---|---|
@Model class Item | @Table nonisolated struct Item |
@Attribute(.unique) | @Column(primaryKey: true) 或 SQL UNIQUE |
@Relationship var tags: [Tag] | var tagIDs: [Tag.ID] + 联接查询 |
@Query var items: [Item] | @FetchAll var items: [Item] |
@Query(sort: \.title) | @FetchAll(Item.order(by: \.title)) |
@Query(filter: #Predicate { $0.isActive }) | @FetchAll(Item.where(\.isActive)) |
@Environment(\.modelContext) | @Dependency(\.defaultDatabase) |
context.insert(item) | Item.insert { Item.Draft(...) }.execute(db) |
context.delete(item) | Item.find(id).delete().execute(db) |
try context.save() | 在 database.write { } 块中自动保存 |
ModelContainer(for:) | prepareDependencies { $0.defaultDatabase = } |
代码示例
SwiftData(之前)
import SwiftData
@Model
class Task {
var id: UUID
var title: String
var isCompleted: Bool
var project: Project?
init(title: String) {
self.id = UUID()
self.title = title
self.isCompleted = false
}
}
struct TaskListView: View {
@Environment(\.modelContext) private var context
@Query(sort: \.title) private var tasks: [Task]
var body: some View {
List(tasks) { task in
Text(task.title)
}
}
func addTask(_ title: String) {
let task = Task(title: title)
context.insert(task)
}
func deleteTask(_ task: Task) {
context.delete(task)
}
}
SQLiteData(之后)
import SQLiteData
@Table
nonisolated struct Task: Identifiable {
let id: UUID
var title = ""
var isCompleted = false
var projectID: Project.ID?
}
struct TaskListView: View {
@Dependency(\.defaultDatabase) var database
@FetchAll(Task.order(by: \.title)) var tasks
var body: some View {
List(tasks) { task in
Text(task.title)
}
}
func addTask(_ title: String) {
try database.write { db in
try Task.insert {
Task.Draft(title: title)
}
.execute(db)
}
}
func deleteTask(_ task: Task) {
try database.write { db in
try Task.find(task.id).delete().execute(db)
}
}
}
主要区别:
class→ 带nonisolated的struct@Model→@Table@Query→@FetchAll@Environment(\.modelContext)→@Dependency(\.defaultDatabase)- 隐式保存 → 显式
database.write { }块 - 直接初始化 → 插入时使用
.Draft类型 @Relationship→ 显式外键 + 联接查询
CloudKit 共享(SwiftData 无法实现)
SwiftData 支持 CloudKit 同步,但不支持共享。SQLiteData 是唯一支持记录共享的 Apple 原生选项。
// 1. Setup SyncEngine with sharing
prepareDependencies {
$0.defaultDatabase = try! appDatabase()
$0.defaultSyncEngine = try SyncEngine(
for: $0.defaultDatabase,
tables: Task.self, Project.self
)
}
// 2. Share a record
@Dependency(\.defaultSyncEngine) var syncEngine
@State var sharedRecord: SharedRecord?
func shareProject(_ project: Project) async throws {
sharedRecord = try await syncEngine.share(record: project) { share in
share[CKShare.SystemFieldKey.title] = "Join my project!"
}
}
// 3. Present native sharing UI
.sheet(item: $sharedRecord) { record in
CloudSharingView(sharedRecord: record)
}
共享功能可用于: 协作列表、共享工作区、家庭共享和团队功能。
性能比较
| 操作 | SwiftData | SQLiteData | 提升 |
|---|---|---|---|
| 插入 50k 条记录 | ~4 分钟 | ~45 秒 | 5x |
| 使用谓词查询 10k 条记录 | ~2 秒 | ~50ms | 40x |
| 内存占用(10k 个对象) | ~80MB | ~20MB | 缩小 4 倍 |
| 冷启动(大型数据库) | ~3 秒 | ~200ms | 15x |
基准数据为近似值,因设备和数据形态而异。
迁移现有用户数据
重要: 仅进行架构迁移会丢失所有用户数据。你必须从 SwiftData 导出数据,再导入 SQLiteData。
// 1. Read all records from SwiftData's backing store
func migrateExistingData(from modelContext: ModelContext, to database: any DatabaseWriter) throws {
// Fetch all SwiftData records
let descriptor = FetchDescriptor<SwiftDataTask>()
let existingTasks = try modelContext.fetch(descriptor)
// 2. Bulk insert into SQLiteData
try database.write { db in
for task in existingTasks {
try SQLiteTask.insert {
SQLiteTask.Draft(
id: task.id,
title: task.title,
isCompleted: task.isCompleted,
projectID: task.project?.id
)
}
.execute(db)
}
}
// 3. Verify migration
let count = try database.read { db in
try SQLiteTask.fetchCount(db)
}
assert(count == existingTasks.count, "Migration count mismatch!")
}
迁移检查清单:
- 删除 SwiftData 容器前导出所有模型
- 迁移关系(获取父级 ID 作为外键)
- 确认迁移前后的记录数一致
- 在确认正常运行前保留 SwiftData 容器作为备份
- 首次启动时使用 UserDefaults 中的版本标记运行迁移
渐进式迁移策略
不必一次性迁移所有内容:
- 为新功能添加 SQLiteData — 现有的简单 CRUD 功能继续使用 SwiftData
- 一次迁移一个模型 — 从性能瓶颈开始
- 初期使用独立数据库 — SQLiteData 用于大型数据和共享,SwiftData 用于偏好设置
- 按需整合 — 或者只要混合使用效果良好,就继续保持混合架构
常见注意事项
关系 → 外键
// SwiftData: implicit relationship
@Relationship var tasks: [Task]
// SQLiteData: explicit column + query
// In child: var projectID: Project.ID
// To fetch: Task.where { $0.projectID.eq(#bind(project.id)) }
级联删除
// SwiftData: @Relationship(deleteRule: .cascade)
// SQLiteData: Define in SQL schema
// "REFERENCES parent(id) ON DELETE CASCADE"
不会自动创建反向关系
// SwiftData: @Relationship(inverse: \Task.project)
// SQLiteData: Query both directions manually
let tasks = Task.where { $0.projectID.eq(#bind(project.id)) }
let project = Project.find(task.projectID)
相关技能:
axiom-sqlitedata— 完整的 SQLiteData API 参考axiom-swiftdata— 如果继续使用 Apple 框架,可参考 SwiftData 模式axiom-grdb— 用于复杂查询的原始 GRDB
历史记录: 更改记录请参阅 git log
评论
支持 Markdown