介绍
核心数据框架已经存在多年了。 在iOS和OS X上,它已被成千上万的应用程序和数百万人使用。Core Data由Apple维护,并且有据可查 。 这是一个成熟的框架,已经证明了它的价值一遍又一遍。
即使Core Data高度依赖Objective-C运行时并与Core Foundation框架巧妙地集成在一起,您仍可以在Swift项目中轻松使用该框架。 结果是一个易于使用的框架来管理对象图,该框架使用优雅,并且在内存使用方面非常有效。
1.先决条件
Core Data框架本身并不难,但是如果您不熟悉iOS或OS X开发,那么我建议您首先阅读有关iOS开发的系列文章 。 它教您iOS开发的基础知识,在本系列的最后,您将拥有足够的知识来从事更复杂的主题,例如Core Data。
正如我所说,Core Data并不像大多数开发人员所想的那样复杂或困难。 但是,我了解到,扎实的基础对于赶上Core Data至关重要。 您需要对Core Data API有适当的了解,以避免不良做法,并确保您不会在使用框架时遇到问题。
核心数据框架的每个组件都有特定的用途和功能。 如果您尝试使用非设计用途的Core Data,将不可避免地陷入框架的困境。
我在本系列的“核心数据”中介绍的内容适用于iOS 7+和OS X 10.10+,但是重点将放在iOS上。 在本系列中,我将使用Xcode 7.1和Swift 2.1。 如果您更喜欢Objective-C,那么我建议阅读我先前关于Core Data framework的系列文章 。
2.学习曲线
最初,Core Data框架似乎让人望而生畏,但是一旦您理解了难题的各个部分是如何结合在一起的,API就会直观,简洁。 这就是大多数开发人员在使用框架时遇到问题的原因。 他们在看到这个难题之前就尝试使用Core Data,他们不知道难题的各个部分如何组合在一起并相互联系。
在本文中,我将帮助您熟悉Core Data stack 。 一旦您了解了核心数据栈的关键角色,该框架将不再那么令人生畏,您甚至可以开始欣赏和欣赏该框架精心设计的API。
与UIKit之类的框架(您可以在不完全了解该框架的情况下使用)相反,Core Data需要对其构建模块有适当的了解。 重要的是要花一些时间来熟悉该框架,我们将在本教程中进行此操作。
3.什么是核心数据?
刚接触Core Data框架的开发人员经常将其与数据库混淆,并期望它可以作为数据库使用。 如果我希望您能从本系列中记住一件事,那就是Core Data不是数据库,您不应该期望它像一个数据库那样工作。
如果不是数据库,什么是核心数据? 广义上讲,核心数据是应用程序的模型层。 这是在渗透了iOS SDK中的模型-视图-控制器模式的模型 。
核心数据既不是您应用程序的数据库,也不是将数据持久保存到数据库的API。 核心数据是管理对象图的框架。 就这么简单。 核心数据可以通过将对象图写入磁盘来保持该对象图的持久性,但这不是框架的主要目标。
4.核心数据栈
如前所述,核心数据栈是核心数据的核心。 它是使核心数据打勾的对象的集合。 堆栈的关键对象是托管对象模型 , 持久性存储协调器和一个或多个托管对象上下文 。 让我们开始快速看一下每个组件。
NSManagedObjectModel
托管对象模型表示应用程序的数据模型。 即使Core Data不是数据库,您也可以将托管对象模型与数据库的模式进行比较,也就是说,它包含有关对象图的模型或实体,它们具有哪些属性以及它们如何关联的信息。另一个。
NSManagedObjectModel
对象通过在初始化期间加载一个或多个数据模型文件来了解数据模型。 我们将在几分钟后看一下它是如何工作的。
NSPersistentStoreCoordinator
顾名思义, NSPersistentStoreCoordinator
对象将数据持久保存到磁盘,并确保持久存储和数据模型兼容。 它在持久性存储和托管对象上下文之间进行中介,还负责加载和缓存数据。 那就对了。 核心数据已内置缓存。
持久存储协调员是核心数据乐队的指挥。 尽管它在核心数据堆栈中起着重要作用,但您很少会直接与其交互。
NSManagedObjectContext
NSManagedObjectContext
对象管理模型对象的集合,即NSManagedObject
类的实例。 一个应用程序可能具有多个托管对象上下文。 每个托管对象上下文均由持久性存储协调器支持。
您可以将托管对象上下文视为在其上使用模型对象的工作台。 您加载它们,对其进行操作,然后将其保存在该工作台上。 加载和保存由持久性存储协调器协调。 您可以有多个工作台,例如,如果您的应用程序是多线程的,这很有用。
尽管可以在线程之间共享托管对象模型和持久性存储协调器,但是绝对不应从不同于创建它们的线程的线程访问托管对象上下文。 在本系列的后面,我们将更详细地讨论多线程。
5.探索核心数据栈
步骤1:专案设定
让我们看一个示例,更详细地研究Core Data堆栈。 通过从“ 文件”菜单中选择“ 新建”>“项目...” ,在Xcode 7中创建一个新项目。 从左侧的iOS>应用程序模板列表中选择单视图应用 程序模板。
将项目命名为Core Data ,将Language设置为Swift ,将Devices设置为iPhone ,并选中标记为Use Core Data的复选框。 告诉Xcode您要将项目文件存储在何处,然后点击创建 。
步骤2:总览
默认情况下,Apple将与Core Data相关的代码放入应用程序的委托类(在我们的示例中为AppDelegate
类)。 打开AppDelegate.swift ,让我们开始探索AppDelegate
类的实现。
在AppDelegate.swift的顶部,您应该看到Core Data框架的import语句。
import UIKit
import CoreData
AppDelegate
类还包含四个惰性存储的属性:
-
NSURL
类型的applicationDocumentsDirectory
-
NSManagedObjectModel
类型的managedObjectModel
- 类型为
NSManagedObjectContext
managedObjectContext
-
persistentStoreCoordinator
型NSPersistentStoreCoordinator
第一个属性applicationDocumentsDirectory
只是访问该应用程序的Documents目录的帮助者。 正如您在下面看到的,该实现非常简单。 NSFileManager
类用于获取应用程序的Documents目录的位置。
lazy var applicationDocumentsDirectory: NSURL = {
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
return urls[urls.count-1]
}()
剩下的三个惰性存储属性更有趣,并且与Core Data框架直接相关。 我们首先要探索managedObjectContext
属性。
步骤3:受管对象上下文
当与Core Data交互时,除了NSManagedObject
之外,您最常使用的类是NSManagedObjectContext
。
lazy var managedObjectContext: NSManagedObjectContext = {
let coordinator = self.persistentStoreCoordinator
var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
请注意, NSManagedObjectContext
对象是在闭包中实例化和配置的。 在闭包中,我们首先获得对持久性存储协调器的引用。 然后,我们实例化NSManagedObjectContext
,并传入.MainQueueConcurrencyType
作为第一个参数。 在本系列的后面,您将了解有关并发类型的更多信息。 通过传入.MainQueueConcurrencyType
,我们指示托管对象上下文将使用主线程的队列来完成其工作。
返回托管对象上下文之前,我们先设置对象的persistentStoreCoordinator
属性。 如果没有持久性存储协调器,则托管对象上下文是无用的。 那不是太困难。 是吗
总之,托管对象上下文管理模型对象的集合, NSManagedObject
类的实例,并保留对持久性存储协调器的引用。 阅读本文的其余部分时,请记住这一点。
第4步:持久性存储协调员
如前所述,在配置受管对象上下文期间访问了persistentStoreCoordinator
属性。 看一看persistentStoreCoordinator
属性的实现,但是不要让它吓到您。 实际上并不那么复杂。
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
} catch {
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
abort()
}
return coordinator
}()
您几乎总是想将Core Data的对象图存储到磁盘上,Apple的persistentStoreCoordinator
属性的实现使用SQLite数据库来完成此操作。 这是核心数据应用程序的常见情况。
在persistentStoreCoordinator
属性的关闭中,我们从实例化NSPersistentStoreCoordinator
类的实例开始,将托管对象模型作为参数传入。 稍后我们将探讨managedObjectModel
属性。
如您所见,创建NSPersistentStoreCoordinator
对象很容易。 但是,如果持久性存储协调器没有任何要管理的持久性存储,则它几乎没有用。 在闭包的其余部分中,我们尝试加载持久性存储并将其添加到持久性存储协调器。
我们首先使用前面看到的applicationDocumentsDirectory
属性指定磁盘上存储的位置。 结果,以NSURL
对象,被传递给addPersistentStoreWithType(_:configuration:URL:options:)
所述的方法NSPersistentStoreCoordinator
类。 如方法名称所示,该方法将持久性存储添加到持久性存储协调器。 该方法接受四个参数。
在此示例中,我们首先指定存储类型NSSQLiteStoreType
。 核心数据还支持二进制存储( NSBinaryStoreType
)和内存存储( NSInMemoryStoreType
)。
第二个参数告诉Core Data持久存储使用哪种配置。 我们传入nil
,它告诉Core Data使用默认配置。 第三个参数是商店的位置,存储在url
。
第四个参数是选项字典,可让我们更改持久性存储的行为。 我们将在本系列的后面部分中重新讨论此方面,并且nil
提供任何信息。
由于addPersistentStoreWithType(_:configuration:URL:options:)
是一种抛出方法,因此我们将方法调用包装在do-catch
语句中。 如果没有错误弹出,则此方法返回NSPersistentStore
对象。 我们不保留对持久性存储的引用,因为一旦将其添加到持久性存储协调器中,我们就无需与之交互。
但是,如果添加持久性存储失败,则意味着应用程序的持久性存储存在问题,我们需要采取必要的步骤来解决该问题。 什么时候发生以及为什么发生是本系列以后部分的主题。
在catch
子句中,我们将所有错误记录到控制台并调用abort
。 您绝对不应在生产环境中调用abort
,因为它会使应用程序崩溃。 在本系列后面的部分中,我们将实施一种不太激进的解决方案。
步骤5:被管理对象模型
难题的第三个也是最后一个是管理对象模型。 让我们看一下managedObjectModel
属性的实现。
lazy var managedObjectModel: NSManagedObjectModel = {
let modelURL = NSBundle.mainBundle().URLForResource("Core_Data", withExtension: "momd")!
return NSManagedObjectModel(contentsOfURL: modelURL)!
}()
实现非常简单。 我们将应用程序模型的位置存储在modelURL
,并在实例化托管对象模型时使用它。
由于初始化程序init(contentsOfURL:)
返回了一个可选参数,因此我们在返回结果之前强制对其进行拆包。 那不是很危险吗? 是的,没有。 不建议强行打开可选包装。 但是,未能初始化托管对象模型意味着应用程序无法在应用程序包中找到数据模型。 如果发生这种情况,那么出了问题,这是应用程序无法控制的。
此时,您可能想知道modelURL
指向的模型是什么,扩展名为.momd的文件是什么。 要回答这些问题,我们需要找出在项目设置过程中Xcode还为我们创建了什么。
在左侧的项目浏览器中 ,您应该看到一个名为Core_Data.xcdatamodeld的文件。 这是已编译为.momd文件的应用程序的数据模型。 托管对象模型使用该.momd文件来创建应用程序的数据模型。
可能有几个数据模型文件。 NSManagedObjectModel
类完全能够将多个数据模型合并为一个,这是Core Data更为强大和高级的功能之一。
核心数据框架还支持数据模型版本控制和迁移。 这确保了存储在持久性存储中的数据不会被破坏。 我们将在本系列的后面部分介绍版本控制和迁移。
项目中的数据模型文件目前为空,这意味着您的数据模型不包含任何实体。 我们将在下一个专门针对数据模型的教程中对此进行补救。
6.放在一起
在总结本文之前,我想向您展示一个图表,该图表说明了Core Data堆栈的三个组成部分。
上图是我们刚才在示例项目中探索的内容的直观表示。 NSPersistentStoreCoordinator
对象是应用程序“核心数据”堆栈的大脑。 它与一个或多个永久性存储进行通信,并确保数据被保存,加载和缓存。
持久性存储协调器通过NSManagedObjectModel
对象了解数据模型,对象图的架构(如果您愿意)。 托管对象模型从一个或多个.momd文件(数据模型的二进制表示)创建应用程序的数据模型。
最后但并非最不重要的一点是,应用程序通过NSManagedObjectContext
类的一个或多个实例访问对象图。 受管对象上下文通过持久性存储协调器了解数据模型,但它不知道或不保留对受管对象模型的引用。 不需要这样的参考。
受管对象上下文向持久性协调器询问数据,并告诉它在必要时保存数据。 这一切都是由Core Data框架为您完成的,您的应用程序很少需要直接与持久性存储协调器对话。
结论
在本文中,我们介绍了Core Data堆栈的关键参与者,持久性存储协调器,托管对象模型和托管对象上下文。 确保您了解每个组件的角色,更重要的是,了解它们如何协同工作以使Core Data发挥其神奇作用。
在本系列的下一部分中,我们将深入研究数据模型。 我们来看一下Xcode中的数据模型编辑器,并创建一些实体,属性和关系。
翻译自: https://code.tutsplus.com/tutorials/core-data-and-swift-core-data-stack--cms-25065