Apple Core Data持久化框架
Apple Core Data持久化框架

Apple Core Data持久化框架

Core Data 是苹果提供的持久化框架,用于在 iOS、macOS、watchOS 和 tvOS 应用中管理数据模型。它允许应用程序的数据保存在磁盘上,并支持数据的创建、读取、更新和删除(CRUD)操作。

核心功能

1、数据持久化

将数据存储在本地 SQLite 数据库中,也可以存储为内存、XML 或二进制文件。

2、对象管理

将数据库的数据转换为 Swift/Objective-C 对象,支持对象关系模型(ORM)。

3、数据查询

使用 NSFetchRequest 来查询数据,可进行复杂的条件过滤、排序。

4、数据变更跟踪

监听数据变化,并自动更新 UI(例如在 UITableView 中)。

5、关系建模

可以建立一对一、一对多或多对多的关系,类似于关系型数据库。

关键组件

1、Managed Object Model (NSManagedObjectModel)

定义数据结构,包括实体、属性和关系。通常通过 .xcdatamodeld 文件进行创建和编辑。

2、Persistent Store Coordinator (NSPersistentStoreCoordinator)

负责连接数据模型和底层的持久化存储(例如 SQLite 文件)。

3、Managed Object Context (NSManagedObjectContext)

负责管理内存中的对象,跟踪数据的修改状态,并在需要时将更改保存到持久存储中。

4、Managed Object (NSManagedObject)

实体数据的具体实例,允许你像使用普通对象一样操作 Core Data 数据。

工作流程

1、创建 NSManagedObjectModel,定义实体和关系。

2、初始化 NSPersistentStoreCoordinator 并连接数据库。

3、通过 NSManagedObjectContext 进行数据的创建、读取、更新和删除。

4、在数据修改后,调用 save() 方法将更改保存到持久存储中。

Xcode创建Core Data文件

添加Core Data文件

1、打开 Xcode 项目,右击项目导航栏,选择“New File…”。

2、选择 Data Model,然后点击 Next。

创建的 .xcdatamodeld 文件内容。

点击“Add Entity”添加一个新的实体。

解析.xcdatamodeld 文件

创建实体后,可以看到3个重要的部分,分别是Attributes(属性)、Relationships(关系)和Fetched Properties(获取属性)。

1、Attributes(属性)

Attributes(属性)是与实体关联的数据字段,类似于数据库表的列。

属性定义了实体的数据内容,包括名称、数据类型和其他约束。

常见属性类型

String → 字符串

Integer 16/32/64 → 整数

Decimal → 十进制数

Double → 双精度浮点数

Float → 单精度浮点数

Boolean → 布尔值(true/false)

Date → 日期和时间

Binary Data → 二进制数据(如图片或文件)

配置属性

Attribute(名称):属性的名字,例如 title、createdAt。

Type(属性类型):定义属性的数据类型。

注意:属性名称必须以小写字母开头,名称只能包含字母、数字或下划线,不能有空格,否则会报:Name must begin with lower case letter类似的错误。

2、Relationships(关系)

定义

Relationships(关系) 连接两个实体,类似于数据库的外键。

关系可以描述一个实体与另一个实体之间的联系。

常见关系类型

1、One-to-One(1:1)

一个 User 只有一个 Profile。

2、One-to-Many(1:N)

一个 User关联多个 MobileNumber。

3、Many-to-Many(M:N)

一个 Student 可以选择多门 Course,每门 Course 也可以有多个 Student。

配置关系

Relationship(关系): 关系的名称,例如 tasks 或 category。

Destination(目标): 目标实体,表示关系连接的另一方。

Inverse(反向关系): 反向关系,建立双向关联。

3、Fetched Properties(获取属性)

Fetched Properties(获取属性) 是一种动态属性,类似于虚拟关系,通过查询(fetch request) 动态获取数据。

与 Relationships 不同,Fetched Properties 不会存储目标数据,只在需要时进行检索。

使用场景

如果想要获取与某个实体相关的对象,但又不希望建立直接关系时。

例如:在 Department 中获取某些符合条件的 Employee。

配置 Fetch Properties

Fetch Property(获取属性): 获取属性的名称。

Predicate(谓词): 筛选目标实体的条件。

添加.xcdatamodeld测试实体

创建一个名为Eurofxrefhist的实体,给属性添加三个字段。

生成Eurofxrefhist+CoreDataClass.swift 和Eurofxrefhist+CoreDataProperties.swift

在 .xcdatamodeld 文件中,选择 Eurofxrefhist实体 → Editor → Create NSManagedObject Subclass。

生成的两个文件会包含 Eurofxrefhist的 Core Data 属性和方法。

关于NSManagedObject Subclass的相关知识,可以进一步阅读《Core Data使用NSManagedObject Subclass管理数据》,这里不做过多的赘述。

SwiftUI配置Core Data

1、配置入口文件
import SwiftUI
import CoreData

@main
struct MyApp: App {
    // 创建 NSPersistentContainer
    let container: NSPersistentContainer

    init() {
        // 加载 xcdatamodeld 文件,确保名字匹配
        container = NSPersistentContainer(name: "YourProjectName")

        // 加载持久化存储
        container.loadPersistentStores { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        }
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(\.managedObjectContext, container.viewContext)
        }
    }
}

NSPersistentContainer(name:) → 通过 xcdatamodeld 文件名来加载数据模型。

container.loadPersistentStores → 加载存储并检查错误。

.environment(\.managedObjectContext, container.viewContext) → 将 viewContext 注入 SwiftUI 环境。

此处涉及NSPersistentContainer的知识,可以进一步阅读《Core Data管理数据模型的NSPersistentContainer》。

2、在 SwiftUI 视图中使用 viewContext
import SwiftUI
import CoreData

struct ContentView: View {
    // 通过 @Environment 读取 viewContext
    @Environment(\.managedObjectContext) private var viewContext

    // 使用 @FetchRequest 获取数据
    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Task.title, ascending: true)],
        animation: .default)
    private var tasks: FetchedResults<Task>

    var body: some View {
        NavigationView {
            List {
                ForEach(tasks) { task in
                    Text(task.title ?? "No Title")
                }
                .onDelete(perform: deleteItems)
            }
            .navigationTitle("Tasks")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(action: addItem) {
                        Label("Add Task", systemImage: "plus")
                    }
                }
            }
        }
    }

    // 添加新任务
    private func addItem() {
        let newTask = Task(context: viewContext)
        newTask.title = "New Task"
        newTask.createdAt = Date()

        saveContext()
    }

    // 删除任务
    private func deleteItems(offsets: IndexSet) {
        offsets.map { tasks[$0] }.forEach(viewContext.delete)
        saveContext()
    }

    // 保存数据
    private func saveContext() {
        do {
            try viewContext.save()
        } catch {
            let nsError = error as NSError
            print("Unresolved error \(nsError), \(nsError.userInfo)")
        }
    }
}

@Environment(\.managedObjectContext) → 从 SwiftUI 环境中读取 viewContext。

@FetchRequest → 直接在 SwiftUI 中通过 FetchRequest 读取数据。

addItem() → 创建新任务并保存到 Core Data。

deleteItems() → 删除数据并保存。

运行项目,测试 Core Data

1、添加任务:点击 + 按钮添加任务。

2、删除任务:左滑删除任务。

3、数据持久化:关闭并重新打开应用,数据会被保留。

此处涉及@FetchRequest的知识,请进一步阅读《SwiftUI获取Core Data数据的@FetchRequest

可选优化

添加 NSFetchedResultsController 来优化数据更新。

处理 Core Data 数据迁移,防止模型变化时崩溃。

实现多线程 Core Data 操作,提升性能。

扩展知识

扩展知识

配置字段参数

在 .xcdatamodeld 文件中,Core Data中的所有属性默认都是可选的。因此在使用@FetchRequest获取Core Data对象时,都会提示字段为可选。

如果想要设置字段为不可选,或者设置默认值等配置,可以打开 .xcdatamodeld 文件,找到对应实体,选择属性,点击右侧的“属性检查器”:

例如取消字段为可选状态,则取消右侧“属性检查器”的Optional选项。

注意:修改后要重新生成 NSManagedObject 子类代码(或使用 @NSManaged 的 Swift class),否则 Swift 代码不会自动同步更改。

持久化控制器

在实际应用中,可能需要在Swift文件中将数据插入到Core Data,通常会考虑创建一个PersistenceController 类,用于管理 Core Data 的堆栈。通常它会包含 NSPersistentContainer。

import CoreData

class PersistenceController {
    static let shared = PersistenceController()

    // Core Data stack
    let container: NSPersistentContainer

    init() {
        container = NSPersistentContainer(name: "YourDataModelName")
        container.loadPersistentStores { (description, error) in
            if let error = error {
                fatalError("Failed to load persistent stores: \(error)")
            }
        }
    }
}

使用正确的模型名称 “YourDataModelName”,这应该与 .xcdatamodeld 文件的名称匹配。

在Swift文件中,将数据插入到Core Data中:

func saveExchangeRates(date: Date, rates: [String: Double]) {
    // 获取 Core Data 上下文
    let context = PersistenceController.shared.container.viewContext
    
    for (currency, rate) in rates {
        // 创建一个新的 ExchangeRate 对象
        let exchangeRate = ExchangeRate(context: context)
        
        // 设置对象的属性
        exchangeRate.date = date
        exchangeRate.currency = currency
        exchangeRate.rateToEuro = rate
    }
    
    // 保存到 Core Data
    do {
        try context.save()  // 保存上下文
        print("汇率数据保存成功")
    } catch {
        print("保存数据失败: \(error)")
    }
}

1)获取上下文 (viewContext):通过 PersistenceController.shared.container.viewContext 获取了 Core Data 的上下文,这是操作 Core Data 对象的核心。

2)创建新的 ExchangeRate 对象:每次循环时,ExchangeRate(context: context) 创建了一个新的实体对象,并绑定到上下文中。这里的 ExchangeRate 是 Core Data 模型中定义的实体。

3)设置实体的属性:对于每个汇率条目,设置了 date(日期)、currency(货币代码)和 rateToEuro(欧元汇率)。这些属性对应 Core Data 模型中定义的字段。

4)保存数据:使用 context.save() 将所有更改保存到持久化存储。如果发生错误,它会抛出异常,捕捉并打印错误信息。

直接使用 NSPersistentContainer 来管理 Core Data

也可以在没有 PersistenceController 类的情况下将数据插入到 Core Data 中。PersistenceController 只是一个管理 Core Data 堆栈的便捷方式,并不是必须的。可以直接使用 NSPersistentContainer 来管理 Core Data,并将数据插入到 Core Data 中。

在Swift代码中创建并使用NSPersistentContainer:

import CoreData

func saveExchangeRates(date: Date, rates: [String: Double]) {
    // 创建并加载 NSPersistentContainer
    let container = NSPersistentContainer(name: "YourDataModelName") // 使用数据模型名称
    container.loadPersistentStores { (description, error) in
        if let error = error {
            fatalError("无法加载持久化存储:\(error)")
        }
    }

    // 获取 Core Data 上下文
    let context = container.viewContext
    
    // 遍历汇率数据并插入到 Core Data
    for (currency, rate) in rates {
        let exchangeRate = ExchangeRate(context: context) // 创建新的 ExchangeRate 实体
        exchangeRate.date = date
        exchangeRate.currency = currency
        exchangeRate.rateToEuro = rate
    }

    // 保存数据到 Core Data
    do {
        try context.save() // 保存上下文
        print("汇率数据保存成功")
    } catch {
        print("保存数据失败: \(error)")
    }
}

1)创建 NSPersistentContainer:在没有 PersistenceController 类的情况下,可以在需要的地方直接创建 NSPersistentContainer。通过 NSPersistentContainer(name: “YourDataModelName”) 来加载数据模型(.xcdatamodeld 文件)。

2)加载持久化存储:调用 container.loadPersistentStores 来加载持久化存储。如果加载失败,程序会终止并打印错误。

3)获取 viewContext:通过 container.viewContext 获取 NSManagedObjectContext,这是进行所有 Core Data 操作的地方。

4)插入数据:创建一个新的 ExchangeRate 实体对象并为其设置属性。可以遍历汇率数据并将每一项保存到 Core Data 中。

5)保存数据:使用 context.save() 将更改保存到持久化存储中。如果保存失败,抛出异常并打印错误。

总结

如果没有 PersistenceController,可以直接在需要的地方使用 NSPersistentContainer 来创建和管理 Core Data 堆栈。

通过 container.viewContext 获取上下文,然后插入数据并保存到持久化存储中。

可以在任何地方创建和使用 NSPersistentContainer,不过在实际应用中,将其封装到一个单独的类(如 PersistenceController)中,会更加方便和结构化。

相关文章

1、Core Data:https://developer.apple.com/documentation/coredata

2、SwiftData数据持久化框架:https://fangjunyu.com/2024/11/06/swiftdata%e6%95%b0%e6%8d%ae%e6%8c%81%e4%b9%85%e5%8c%96%e6%a1%86%e6%9e%b6/

3、Core Data使用NSManagedObject Subclass管理数据:https://fangjunyu.com/2025/03/27/core-data%e4%bd%bf%e7%94%a8nsmanagedobject-subclass%e7%ae%a1%e7%90%86%e6%95%b0%e6%8d%ae/

4、Core Data管理数据模型的NSPersistentContainer:https://fangjunyu.com/2025/03/29/core-data%e7%ae%a1%e7%90%86%e6%95%b0%e6%8d%ae%e6%a8%a1%e5%9e%8b%e7%9a%84nspersistentcontainer/

5、SwiftUI获取Core Data数据的@FetchRequest:https://fangjunyu.com/2025/03/30/swiftui%e8%8e%b7%e5%8f%96core-data%e6%95%b0%e6%8d%ae%e7%9a%84fetchrequest/

6、Core Data预览报错问题:https://fangjunyu.com/2025/03/30/core-data%e9%a2%84%e8%a7%88%e6%8a%a5%e9%94%99%e9%97%ae%e9%a2%98/

7、Core Data获取数据的NSFetchRequest:https://fangjunyu.com/2025/04/10/core-data%e8%8e%b7%e5%8f%96%e6%95%b0%e6%8d%ae%e7%9a%84nsfetchrequest/

8、Core Data管理数据生命周期的NSManagedObjectContext:https://fangjunyu.com/2025/03/30/core-data%e7%ae%a1%e7%90%86%e6%95%b0%e6%8d%ae%e7%94%9f%e5%91%bd%e5%91%a8%e6%9c%9f%e7%9a%84nsmanagedobjectcontext/

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注