移动/游戏
用 SwiftData 做 iOS 数据持久化:建模、查询…
在 iOS 26+/Swift 6.3 应用中使用 SwiftData 定义 @Model、配置 ModelContainer、执行 CRUD、编写 @Query/#Predicate、做 schema 迁移、接入 CloudKit 同步以及与 Core Data 共存时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
用 SwiftData 做 iOS 数据通用
解决思路
- 用 @Model 标注 class(不是 struct),它会合成 PersistentModel 一致性;模型实例绑定到 context/actor,跨 actor 时传 PersistentIdentifier 而不是实例本身。
- 在 @Model 中按需使用 @Attribute 选项:.externalStorage、.unique、.spotlight、.allowsCloudEncryption、.preserveValueOnDeletion、.ephemeral、.transformable(by:);重命名用 @Attribute(originalName: "old_name")。
- 用 @Relationship 指定 deleteRule(.cascade/.nullify(默认)/.deny/.noAction),并显式写 inverse: 以保证行为可靠;iOS 18+ 可用单向关系 inverse: nil。
- 用 #Unique<Person>([\.firstName, \.lastName])(iOS 18+)声明复合唯一约束;iOS 26+ 支持 @Model 继承。
- 只使用受支持的类型:Bool、Int/UInt 变体、Float、Double、String、Date、Data、URL、UUID、Decimal、Array、Dictionary、Set、Codable 枚举、Codable 结构体及其他兼容 Codable 值类型,以及指向 @Model 类的关系。
- 用 ModelContainer(for:) 创建基础容器;用 ModelConfiguration("Store", isStoredInMemoryOnly:groupContainer:cloudKitDatabase:) 做配置;带迁移计划时用 ModelContainer(for:migrationPlan:);预览/测试用 ModelConfiguration(isStoredInMemoryOnly: true)。
- 接入 CloudKit 时先做 Capabilities 判定:Xcode target 启用 iCloud 能力并勾选 CloudKit 与目标容器,同时开启 Background Modes > Remote notifications;否则即使设置了 cloudKitDatabase 也不会完整同步。
- CloudKit schema 兼容性:不要用 @Attribute(.unique) 或 #Unique;关系必须可选、必要时显式 inverse、避免 .deny;大 Data 用 @Attribute(.externalStorage)。
- CloudKit 标量属性:不要为了 CloudKit 把所有标量都设为可选;当初始化器、默认值或迁移能提供有效值时,保持必需标量非可选。
- CloudKit schema 发布流程:仅在非生产构建中初始化开发 schema,在 CloudKit Dashboard 验证,发布前先 promote,生产环境变更只做增量添加。
- 执行破坏性批量操作或迁移前,先在一次性副本上跑精确的 predicate 或版本跳转,记录受影响的 identifier/数量;用显式事务/保存语义执行,重新 fetch 并校验值、关系、数量与不变量;失败时修正 predicate/schema 并恢复干净 fixture 再重试,绝不盲目重放破坏性操作。
- CRUD:CREATE 用 modelContext.insert(trip) 后 try modelContext.save()(或依赖 autosave);READ 用 try modelContext.fetch(FetchDescriptor<Trip>(predicate:sortBy:));UPDATE 直接改属性由 autosave 处理;DELETE 用 modelContext.delete(trip) 或 try modelContext.delete(model: Trip.self, where: #Predicate { $0.isFavorite == false });原子事务用 try modelContext.transaction { ... }。
- 在 SwiftUI 中用 @Query(filter:sort:order:) 做响应式展示;动态查询在 init 中通过 _trips = Query(filter:sort:) 构造;也可用 @Query(FetchDescriptor) 形式。
- #Predicate 只使用受支持表达式:==、!=、<、<=、>、>=、&&、||、!、contains()、allSatisfy()、filter()、starts(with:)、localizedStandardContains()、caseInsensitiveCompare()、算术、条件表达式、可选链与绑定、nil 合并、类型转换;避免循环、嵌套声明、修改操作和任意不支持的方法调用。
- FetchDescriptor 可设置 fetchLimit、fetchOffset、includePendingChanges、propertiesToFetch、relationshipKeyPathsForPrefetching;用 fetch 取对象、fetchCount 取数量、fetchIdentifiers 取 ID、enumerate(batchSize:) 做批量遍历。
- Schema 迁移:用 VersionedSchema 定义各版本(含 versionIdentifier 与 models),用 SchemaMigrationPlan 汇总 schemas 与 stages;简单变更用 MigrationStage.lightweight(fromVersion:toVersion:),数据转换用 MigrationStage.custom(fromVersion:toVersion:willMigrate:didMigrate:)。
- Lightweight 可处理:新增可选/带默认值的属性、重命名(originalName)、删除属性、新增模型类型;确认 stage 列表覆盖所有支持的版本跳转,并对每个旧 store 的干净副本执行迁移并断言迁移后数据。
- 与 Core Data 共存时:让 SwiftData 与 Core Data 指向同一个 SQLite store URL;在 @Model 中匹配 Core Data 的实体名、属性名、类型与关系形状;持久化名不同时用 @Attribute(originalName:);迁移期间同一实体只由一个栈写入,不要两个栈同时写。
- 并发用 @ModelActor:在 actor 内用 modelContext.insert 与 try modelContext.save()(@ModelActor 中必须显式 save);用 self[tripID, as: Trip.self] 按 PersistentIdentifier 取对象;ModelContainer 是 Sendable,ModelContext 不是,必须在其创建 actor 上使用;跨 actor 只传 PersistentIdentifier,绝不传 @Model 对象。
- SwiftUI 集成:在 App 的 Scene 上用 .modelContainer(for: [Trip.self, LivingAccommodation.self]);视图中用 @Environment(\.modelContext) 做删除等操作;#Preview 中用 ModelConfiguration(isStoredInMemoryOnly: true) 创建容器并插入示例数据后 .modelContainer(container)。
- 避免常见错误:@Model 不要用在 struct 上;@Transient 必须有默认值;视图层级必须挂 .modelContainer 否则 @Query 返回空;不要跨 actor 传模型对象;不要在错误 actor 上用 ModelContext;#Predicate 不要用不支持表达式或流程控制;@ModelActor 中不要漏 save;不要对 @Model 用 ObservableObject/@Published;非可选关系必须有默认值否则重建时崩溃;cascade 要配 inverse;后台数据工作不要用 DispatchQueue 而用 @ModelActor。
- 按 Review Checklist 自检:@Model 是带指定初始化器的 class;@Transient 有默认值;关系有 deleteRule 与 inverse;.modelContainer 挂在 scene/根视图;SwiftUI 用 @Query;#Predicate 只用受支持操作符;后台用 @ModelActor;跨 actor 用 PersistentIdentifier;schema 变更配 VersionedSchema + SchemaMigrationPlan;大数据用 @Attribute(.externalStorage);CloudKit 模型避免唯一约束、关系可选、避免 .deny、不盲目可选化标量;CloudKit 同步检查 iCloud+CloudKit、Remote notifications 与生产 schema 发布;@ModelActor 方法显式 save();预览用 isStoredInMemoryOnly: true;SwiftUI 视图访问的 @Model 类通过 @ModelActor 或 MainActor 隔离在主线程。
适用边界 · 注意事项
- 纯 Core Data 栈搭建、NSManagedObjectContext、NSFetchRequest 与 Core Data 批量操作应交给 core-data 技能,不属于本技能范围。
- 目标平台低于 iOS 26 / Swift 6.3 时,部分特性(如 @Model 继承)不可用。
- 未配置 iCloud 能力与 Remote notifications 时,仅设置 cloudKitDatabase 无法完成 CloudKit 自动同步。