名称: iOS 数据持久化 (Core Data/Realm) 描述: 专精于 iOS 本地数据持久化解决方案的专业技能 版本: 1.0.0 类别: iOS 数据存储 标识符: ios-persistence 状态: 活跃
iOS 数据持久化技能
概述
此技能提供针对 iOS 本地数据持久化解决方案(包括 Core Data 和 Realm)的专门能力。它支持设计数据模型、实现迁移、配置 iCloud 同步以及优化数据库性能。
允许使用的工具
bash- 执行 xcodebuild 和 swift 命令read- 分析 Core Data 模型和 Realm 模式write- 生成模型类和配置edit- 更新现有的持久化代码glob- 搜索模型文件和配置grep- 在持久化代码中搜索模式
能力
Core Data
-
模型设计
- 设计 .xcdatamodel 文件
- 生成 NSManagedObject 子类
- 配置实体关系
- 设置获取请求模板
- 定义验证规则
-
CRUD 操作
- 使用谓词实现获取请求
- 配置排序和分组
- 处理批量操作
- 实现级联删除
- 配置唯一性约束
-
数据迁移
- 配置轻量级迁移
- 实现自定义迁移映射
- 处理版本兼容性
- 设计渐进式迁移路径
- 测试迁移场景
-
CloudKit 集成
- 配置 NSPersistentCloudKitContainer
- 处理同步冲突
- 实现公共/私有数据库
- 配置共享参与者
- 监控同步状态
-
性能优化
- 配置后台上下文
- 实现批量插入/更新
- 使用 NSBatchDeleteRequest
- 配置获取结果控制器
- 通过故障机制优化内存
Realm Swift
-
模式定义
- 定义 Realm Object 类
- 配置主键
- 设置关系 (List, LinkingObjects)
- 定义索引属性
- 配置可选属性
-
查询与过滤
- 实现 Results 查询
- 配置排序
- 使用谓词和过滤器
- 处理实时查询
- 实现分组结果
-
数据迁移
- 配置模式版本
- 实现迁移块
- 处理属性重命名
- 添加/移除属性
- 在迁移期间转换数据
-
同步配置
- 配置 Realm Sync
- 处理冲突解决
- 实现离线优先模式
- 配置灵活同步订阅
- 监控同步进度
目标流程
此技能与以下流程集成:
ios-core-data-implementation.js- Core Data 设置与使用offline-first-architecture.js- 离线数据策略mobile-security-implementation.js- 安全数据存储
依赖项
必需
- Xcode 15+
- Swift 5.9+
- iOS 17+ (用于最新功能)
可选
- Realm SDK
- CloudKit 权限
- Core Data 编辑器
配置
Core Data 堆栈
// Persistence/PersistenceController.swift
import CoreData
import CloudKit
final class PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentCloudKitContainer
init(inMemory: Bool = false) {
container = NSPersistentCloudKitContainer(name: "MyApp")
if inMemory {
container.persistentStoreDescriptions.first?.url = URL(fileURLWithPath: "/dev/null")
}
// 配置 CloudKit
guard let description = container.persistentStoreDescriptions.first else {
fatalError("无法获取持久化存储描述")
}
description.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(
containerIdentifier: "iCloud.com.example.myapp"
)
description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
container.loadPersistentStores { description, error in
if let error = error {
fatalError("无法加载持久化存储: \(error)")
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
}
// MARK: - 预览支持
static var preview: PersistenceController = {
let controller = PersistenceController(inMemory: true)
// 添加示例数据
return controller
}()
}
Realm 配置
// Persistence/RealmManager.swift
import RealmSwift
final class RealmManager {
static let shared = RealmManager()
private init() {
configureRealm()
}
private func configureRealm() {
let config = Realm.Configuration(
schemaVersion: 1,
migrationBlock: { migration, oldSchemaVersion in
if oldSchemaVersion < 1 {
// 迁移逻辑
}
}
)
Realm.Configuration.defaultConfiguration = config
}
var realm: Realm {
try! Realm()
}
}
使用示例
Core Data 实体
// Models/Item+CoreDataClass.swift
import Foundation
import CoreData
@objc(Item)
public class Item: NSManagedObject {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Item> {
return NSFetchRequest<Item>(entityName: "Item")
}
@NSManaged public var id: UUID
@NSManaged public var title: String
@NSManaged public var createdAt: Date
@NSManaged public var isCompleted: Bool
@NSManaged public var category: Category?
}
extension Item {
static func create(
in context: NSManagedObjectContext,
title: String,
category: Category? = nil
) -> Item {
let item = Item(context: context)
item.id = UUID()
item.title = title
item.createdAt = Date()
item.isCompleted = false
item.category = category
return item
}
static func fetchAll(in context: NSManagedObjectContext) -> [Item] {
let request = fetchRequest()
request.sortDescriptors = [NSSortDescriptor(keyPath: \Item.createdAt, ascending: false)]
return (try? context.fetch(request)) ?? []
}
static func fetchIncomplete(in context: NSManagedObjectContext) -> [Item] {
let request = fetchRequest()
request.predicate = NSPredicate(format: "isCompleted == NO")
request.sortDescriptors = [NSSortDescriptor(keyPath: \Item.createdAt, ascending: false)]
return (try? context.fetch(request)) ?? []
}
}
Core Data 仓库
// Data/Repository/ItemRepository.swift
import Foundation
import CoreData
import Combine
protocol ItemRepositoryProtocol {
func fetchItems() -> AnyPublisher<[Item], Error>
func addItem(title: String) -> AnyPublisher<Item, Error>
func updateItem(_ item: Item) -> AnyPublisher<Void, Error>
func deleteItem(_ item: Item) -> AnyPublisher<Void, Error>
}
final class ItemRepository: ItemRepositoryProtocol {
private let container: NSPersistentContainer
private let backgroundContext: NSManagedObjectContext
init(container: NSPersistentContainer = PersistenceController.shared.container) {
self.container = container
self.backgroundContext = container.newBackgroundContext()
self.backgroundContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
}
func fetchItems() -> AnyPublisher<[Item], Error> {
Future { [weak self] promise in
guard let self = self else { return }
self.backgroundContext.perform {
do {
let items = try Item.fetchAll(in: self.backgroundContext)
promise(.success(items))
} catch {
promise(.failure(error))
}
}
}
.eraseToAnyPublisher()
}
func addItem(title: String) -> AnyPublisher<Item, Error> {
Future { [weak self] promise in
guard let self = self else { return }
self.backgroundContext.perform {
let item = Item.create(in: self.backgroundContext, title: title)
do {
try self.backgroundContext.save()
promise(.success(item))
} catch {
self.backgroundContext.rollback()
promise(.failure(error))
}
}
}
.eraseToAnyPublisher()
}
func updateItem(_ item: Item) -> AnyPublisher<Void, Error> {
Future { [weak self] promise in
guard let self = self else { return }
self.backgroundContext.perform {
do {
try self.backgroundContext.save()
promise(.success(()))
} catch {
self.backgroundContext.rollback()
promise(.failure(error))
}
}
}
.eraseToAnyPublisher()
}
func deleteItem(_ item: Item) -> AnyPublisher<Void, Error> {
Future { [weak self] promise in
guard let self = self else { return }
self.backgroundContext.perform {
self.backgroundContext.delete(item)
do {
try self.backgroundContext.save()
promise(.success(()))
} catch {
self.backgroundContext.rollback()
promise(.failure(error))
}
}
}
.eraseToAnyPublisher()
}
}
Realm 对象
// Models/TaskObject.swift
import RealmSwift
class TaskObject: Object, Identifiable {
@Persisted(primaryKey: true) var id: ObjectId
@Persisted var title: String = ""
@Persisted var dueDate: Date?
@Persisted var isCompleted: Bool = false
@Persisted var priority: Int = 0
@Persisted var tags: List<TagObject>
@Persisted(originProperty: "tasks") var project: LinkingObjects<ProjectObject>
convenience init(title: String, dueDate: Date? = nil, priority: Int = 0) {
self.init()
self.title = title
self.dueDate = dueDate
self.priority = priority
}
}
class TagObject: Object, Identifiable {
@Persisted(primaryKey: true) var id: ObjectId
@Persisted(indexed: true) var name: String = ""
@Persisted var color: String = "#000000"
}
class ProjectObject: Object, Identifiable {
@Persisted(primaryKey: true) var id: ObjectId
@Persisted var name: String = ""
@Persisted var tasks: List<TaskObject>
}
Realm 仓库
// Data/Repository/TaskRealmRepository.swift
import Foundation
import RealmSwift
import Combine
protocol TaskRepositoryProtocol {
func fetchTasks() -> AnyPublisher<[TaskObject], Error>
func addTask(_ task: TaskObject) -> AnyPublisher<Void, Error>
func updateTask(_ task: TaskObject, with updates: (TaskObject) -> Void) -> AnyPublisher<Void, Error>
func deleteTask(_ task: TaskObject) -> AnyPublisher<Void, Error>
}
final class TaskRealmRepository: TaskRepositoryProtocol {
private let realm: Realm
init(realm: Realm = RealmManager.shared.realm) {
self.realm = realm
}
func fetchTasks() -> AnyPublisher<[TaskObject], Error> {
Just(Array(realm.objects(TaskObject.self).sorted(byKeyPath: "dueDate")))
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
}
func addTask(_ task: TaskObject) -> AnyPublisher<Void, Error> {
Future { [weak self] promise in
guard let self = self else { return }
do {
try self.realm.write {
self.realm.add(task)
}
promise(.success(()))
} catch {
promise(.failure(error))
}
}
.eraseToAnyPublisher()
}
func updateTask(_ task: TaskObject, with updates: (TaskObject) -> Void) -> AnyPublisher<Void, Error> {
Future { [weak self] promise in
guard let self = self else { return }
do {
try self.realm.write {
updates(task)
}
promise(.success(()))
} catch {
promise(.failure(error))
}
}
.eraseToAnyPublisher()
}
func deleteTask(_ task: TaskObject) -> AnyPublisher<Void, Error> {
Future { [weak self] promise in
guard let self = self else { return }
do {
try self.realm.write {
self.realm.delete(task)
}
promise(.success(()))
} catch {
promise(.failure(error))
}
}
.eraseToAnyPublisher()
}
}
质量门限
数据完整性
- 所有实体都有适当的验证
- 在真实数据上测试迁移
- 保持关系完整性
- 无孤立数据
性能
- 使用限制优化获取请求
- 繁重操作用后台上下文
- 批量更改用批量操作
- 在频繁查询的属性上正确建立索引
测试
- 仓库的单元测试
- 使用示例数据的迁移测试
- 线程安全的并发测试
相关技能
swift-swiftui- iOS 应用开发mobile-security- 安全数据存储offline-storage- 跨平台离线模式
版本历史
- 1.0.0 - 初始版本,支持 Core Data 和 Realm