iOS数据持久化技能 iOSPersistence(CoreData/Realm)

本技能专注于为 iOS 应用提供专业的本地数据存储与管理解决方案,涵盖 Core Data 和 Realm 两大主流框架。核心能力包括:数据模型设计、CRUD操作实现、数据迁移策略、iCloud/CloudKit同步配置、数据库性能优化、以及离线优先架构支持。适用于需要高效、稳定、可扩展本地数据存储的 iOS 应用开发场景,如笔记应用、任务管理、电商购物车、离线阅读等。关键词:iOS数据存储,Core Data,Realm,数据持久化,本地数据库,Swift开发,移动端数据库,数据迁移,云同步,离线应用。

移动开发 0 次安装 0 次浏览 更新于 2/25/2026

名称: 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

  1. 模型设计

    • 设计 .xcdatamodel 文件
    • 生成 NSManagedObject 子类
    • 配置实体关系
    • 设置获取请求模板
    • 定义验证规则
  2. CRUD 操作

    • 使用谓词实现获取请求
    • 配置排序和分组
    • 处理批量操作
    • 实现级联删除
    • 配置唯一性约束
  3. 数据迁移

    • 配置轻量级迁移
    • 实现自定义迁移映射
    • 处理版本兼容性
    • 设计渐进式迁移路径
    • 测试迁移场景
  4. CloudKit 集成

    • 配置 NSPersistentCloudKitContainer
    • 处理同步冲突
    • 实现公共/私有数据库
    • 配置共享参与者
    • 监控同步状态
  5. 性能优化

    • 配置后台上下文
    • 实现批量插入/更新
    • 使用 NSBatchDeleteRequest
    • 配置获取结果控制器
    • 通过故障机制优化内存

Realm Swift

  1. 模式定义

    • 定义 Realm Object 类
    • 配置主键
    • 设置关系 (List, LinkingObjects)
    • 定义索引属性
    • 配置可选属性
  2. 查询与过滤

    • 实现 Results 查询
    • 配置排序
    • 使用谓词和过滤器
    • 处理实时查询
    • 实现分组结果
  3. 数据迁移

    • 配置模式版本
    • 实现迁移块
    • 处理属性重命名
    • 添加/移除属性
    • 在迁移期间转换数据
  4. 同步配置

    • 配置 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