axiom-sqlitedata-migration
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMigrating from SwiftData to SQLiteData
从SwiftData迁移到SQLiteData
When to Switch
何时切换
┌─────────────────────────────────────────────────────────┐
│ 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? │
├─────────────────────────────────────────────────────────┤
│ │
│ 处理1万条以上记录时存在性能问题? │
│ 是 → 使用SQLiteData(处理大型数据集时速度快10-50倍) │
│ │
│ 需要CloudKit记录共享(而非仅同步)? │
│ 是 → 使用SQLiteData(SwiftData不支持记录共享) │
│ │
│ 需要跨多张表执行复杂查询? │
│ 是 → 使用SQLiteData + 必要时使用原生GRDB │
│ │
│ 需要为Swift 6并发模型提供Sendable类型的模型? │
│ 是 → 使用SQLiteData(值类型,而非类类型) │
│ │
│ 测试@Model类的过程很繁琐? │
│ 是 → 使用SQLiteData(纯结构体,易于模拟) │
│ │
│ 对于简单CRUD操作,SwiftData使用体验良好? │
│ 是 → 继续使用SwiftData(基础应用场景下更简单) │
│ │
└─────────────────────────────────────────────────────────┘Pattern Equivalents
模式对应关系
| SwiftData | SQLiteData |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| Automatic in |
| |
| SwiftData | SQLiteData |
|---|---|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| Automatic in |
| |
Code Example
代码示例
SwiftData (Before)
swift
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 (After)
swift
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)
}
}
}Key differences:
- →
classwithstructnonisolated - →
@Model@Table - →
@Query@FetchAll - →
@Environment(\.modelContext)@Dependency(\.defaultDatabase) - Implicit save → Explicit block
database.write { } - Direct init → type for inserts
.Draft - → Explicit foreign key + join
@Relationship
SwiftData(迁移前)
swift
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(迁移后)
swift
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的nonisolatedstruct - →
@Model@Table - →
@Query@FetchAll - →
@Environment(\.modelContext)@Dependency(\.defaultDatabase) - 隐式保存 → 显式的代码块
database.write { } - 直接初始化 → 使用类型执行插入操作
.Draft - → 显式外键 + 关联查询
@Relationship
CloudKit Sharing (SwiftData Can't Do This)
CloudKit共享(SwiftData不支持此功能)
SwiftData supports CloudKit sync but NOT sharing. SQLiteData is the only Apple-native option for record sharing.
swift
// 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)
}Sharing enables: Collaborative lists, shared workspaces, family sharing, team features.
SwiftData支持CloudKit同步但不支持共享。SQLiteData是目前唯一支持记录共享的苹果原生方案。
swift
// 1. 配置带共享功能的SyncEngine
prepareDependencies {
$0.defaultDatabase = try! appDatabase()
$0.defaultSyncEngine = try SyncEngine(
for: $0.defaultDatabase,
tables: Task.self, Project.self
)
}
// 2. 共享一条记录
@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. 展示原生共享界面
.sheet(item: $sharedRecord) { record in
CloudSharingView(sharedRecord: record)
}共享功能可实现: 协作列表、共享工作区、家庭共享、团队协作功能。
Performance Comparison
性能对比
| Operation | SwiftData | SQLiteData | Improvement |
|---|---|---|---|
| Insert 50k records | ~4 minutes | ~45 seconds | 5x |
| Query 10k with predicate | ~2 seconds | ~50ms | 40x |
| Memory (10k objects) | ~80MB | ~20MB | 4x smaller |
| Cold launch (large DB) | ~3 seconds | ~200ms | 15x |
Benchmarks approximate, vary by device and data shape.
| 操作 | SwiftData | SQLiteData | 性能提升 |
|---|---|---|---|
| 插入5万条记录 | ~4分钟 | ~45秒 | 5倍 |
| 带谓词查询1万条记录 | ~2秒 | ~50毫秒 | 40倍 |
| 内存占用(1万个对象) | ~80MB | ~20MB | 缩小4倍 |
| 冷启动(大型数据库) | ~3秒 | ~200毫秒 | 15倍 |
基准测试结果为近似值,具体取决于设备和数据结构。
Gradual Migration Strategy
渐进式迁移策略
You don't have to migrate everything at once:
- Add SQLiteData for new features — Keep SwiftData for existing simple CRUD
- Migrate one model at a time — Start with the performance bottleneck
- Use separate databases initially — SQLiteData for heavy data/sharing, SwiftData for preferences
- Consolidate if needed — Or keep hybrid if it works
你无需一次性完成全部迁移:
- 为新功能引入SQLiteData — 现有简单CRUD操作继续使用SwiftData
- 逐个迁移模型 — 从性能瓶颈对应的模型开始迁移
- 初始阶段使用独立数据库 — SQLiteData处理大数据/共享场景,SwiftData处理偏好设置
- 按需合并 — 如果混合架构运行良好,也可保持现状
Common Gotchas
常见注意事项
Relationships → Foreign Keys
关联关系 → 外键
swift
// SwiftData: implicit relationship
@Relationship var tasks: [Task]
// SQLiteData: explicit column + query
// In child: var projectID: Project.ID
// To fetch: Task.where { $0.projectID == project.id }swift
// SwiftData: 隐式关联
@Relationship var tasks: [Task]
// SQLiteData: 显式列 + 查询
// 子模型中:var projectID: Project.ID
// 查询方式:Task.where { $0.projectID == project.id }Cascade Deletes
级联删除
swift
// SwiftData: @Relationship(deleteRule: .cascade)
// SQLiteData: Define in SQL schema
// "REFERENCES parent(id) ON DELETE CASCADE"swift
// SwiftData: @Relationship(deleteRule: .cascade)
// SQLiteData: 在SQL schema中定义
// "REFERENCES parent(id) ON DELETE CASCADE"No Automatic Inverse
无自动反向关联
swift
// SwiftData: @Relationship(inverse: \Task.project)
// SQLiteData: Query both directions manually
let tasks = Task.where { $0.projectID == project.id }
let project = Project.find(task.projectID)Related Skills:
- — Full SQLiteData API reference
axiom-sqlitedata - — SwiftData patterns if staying with Apple's framework
axiom-swiftdata - — Raw GRDB for complex queries
axiom-grdb
History: See git log for changes
swift
// SwiftData: @Relationship(inverse: \Task.project)
// SQLiteData: 手动查询两个方向
let tasks = Task.where { $0.projectID == project.id }
let project = Project.find(task.projectID)相关技能:
- — 完整的SQLiteData API参考
axiom-sqlitedata - — 若继续使用苹果框架,可参考SwiftData相关模式
axiom-swiftdata - — 复杂查询可使用原生GRDB
axiom-grdb
历史记录: 查看git日志了解变更