在单个设备上持久化(persist)或缓存(cache)数据,并且支持撤销(undo)。
使用Core Data来保存你的应用程序的**永久性(permanent)数据供离线使用,缓存临时(temporary)**数据,并在单个设备上为应用程序添加撤销功能。
通过Core Data数据模型编辑器,你可以定义数据类型和关系,并生成(generate)相应的类定义。Core Data可以在运行时管理对象实例(instances),并提供以下特性(features)。
持久化(Persistence)
Core Data将对象**映射到(mapping ... to)存储的细节抽象(abstracts)出来,使得在不直接管理(administering)**数据库的情况下从Swift和OC中保存数据变得很容易。
撤回和重做
Core Data 的撤回管理器会跟踪变化,并且可以单个(individually)、**整组(groups)或者一次性地(all at once)回滚(roll ... back)**数据,可以方便地使你的程序支持撤回和重做。
后台数据任务
尽可能地(potentially)将可能阻塞UI(UI-blocking)的数据任务(例如解析(parsing)JSON到对象)放在后台(in the background),然后可以缓存或者存储(store)结果以减少(reduce)服务器往返(roundtrips)。
与视图同步(synchronization)
Core Data还通过为表和集合(collection)视图提供(providing)数据源,帮助保存视图和数据同步(synchronized)。
版本控制(Versioning)与迁移(Migration)
Core Data 包含随着应用程序的发展(evolves)而对数据模型进行版本控制(versioning)和迁移(migrating)用户数据的机制(mechanisms)。
创建数据模型
想要使用 Core Data 功能的第一步就是创建一个数据模型文件,然后在该文件中定义应用程序对象的结构,包括它们的对象类型、属性和关系。
你可以在创建Xcode项目时选择添加Core Data模型文件到你的项目中,你也可以将模型文件添加到一个已有的项目中。
创建项目时添加Core Data
在创建项目的弹窗中,选择使用Core Data选项。
之后你就可以在你的项目中看到后缀名为 .xcdatamodeld 的文件
添加Core Data模型文件到一个已有项目中
选择 File -> New -> File 在打开的弹窗中选择 iOS 分组中的Data Model选项。
点击下一步(Next),设置模型文件的名字,并选择导入到本项目中。
之后你就会发现一个后缀为 .xcdatamodeld 的文件已经添加到你的项目中了。
创建Core Data数据栈
当你创建了数据模型文件后,接下来就是设置模型层类以辅助(collaboratively)支持(support)你的应用。这些类统称为Core Data Stack(核心数据栈)。
-
NSManagedObjectModel的**实例(instance)表示应用程序的模型文件,该文件描述(describing)**了程序的类型(types),属性(properties)以及关系(relationships)。 -
NSMangedObjectContext实例(instance)可以跟踪(tracks)程序类型实例(instance of your app's types)的变化(changes)。 -
NSPersistentStoreCoordinator实例(instance)保存(saves)并从存储(store)里获取(fetches)程序类型的实例(instances of your app's types)。 -
NSPersistentContainer实例一次性设置模型(model)、上下文(context)以及存储(store)协管器(coordinator)。
初始化Persistent Container
通常来说,Core Data的初始化(initialize)是在应用创建(startup)的时候(during)。使用**懒加载(lazy)变量(variable)延迟(defer)创建持久化容器(persistent container)实例,直到程序代理(delegate)**第一次使用 Core Data。
如果你在创建Xcode项目是选择了Core Data选项,则**模版(template)会自动(automaticallye)**包含这些设置代码。
class AppDelegate: UIResponder, UIApplicationDelegate {
...
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "DataModel")
container.loadPersistentStores { description, error in
if let error = error {
fatalError("Unable to load persistent stores: \(error)")
}
}
return container
}()
...
}
- 声明(declare)一个
NSPersistentContainer类型的懒加载(lazy)变量(variable)。 - 创建一个持久化容器(persistent container)实例(instance),将数据模型文件名传递(passing)给它的初始化器(initializer)。
- 加载(load)持久化存储(persistence stores),如果不存在持久化存储的实例,则会创建一个。
一次创建之后,持久化容器将分别(respectively)在其managedObjectModel、viewContext以及persistentStoreCoordinator属性中保存对模型、上下文和存储协调器实例的引用(references)。
之后可以将容器的引用传递到用户界面中。
将持久化容器引用传递给视图控制器
在程序的根视图,import CoreData 并且创建一个变量来存放持久化容器的引用。
import UIKit
import CoreData
class ViewController: UIViewController {
var container: NSPersistentContainer!
override func viewDidLoad() {
super.viewDidLoad()
guard container != nil else {
fatalError("This view needs a persistent container.")
}
// The persistent container is available.
}
}
回到程序代理。在 application(_:didFinishLaunchingWithOptions:)中,设置根组件控制器,并设置持久化容器。
class AppDelegate: UIResponder, UIApplicationDelegate {
...
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if let rootVC = window?.rootViewController as? ViewController {
rootVC.container = persistentContainer
}
return true
}
...
}
为了将持久化容器**传递(pass)到其他(additional)视图控制器中,在每个视图控制器中重复(repeat)创建(creation)一个容器变量,并在视图的上层(previous)**视图使用prepare(for:sender:)设置它们的值。
class ViewController: UIViewController {
...
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let nextVC = segue.destination as? NextViewController {
nextVC.container = container
}
}
}
子类化(subclass)持久化容器
NSPersistentContainer可以(intended)被子类化(to be subclassed)。子类是存放 Core Data 相关代码的区域(place),可以**方便(convenient)我们进行数据的管理,例如设置一个返回数据子集(subsets of data)**或者将数据持久化到磁盘的函数。
import CoreData
class PersistentContainer: NSPersistentContainer {
func saveContext(backgroundContext: NSManagedObjectContext? = nil) {
let context = backgroundContext ?? viewContext
guard context.hasChanges else { return }
do {
try context.save()
} catch let error as NSError {
print("Error: \(error), \(error.userInfo)")
}
}
}
上面(above)的示例(example)向容器中添加了一个saveContext函数,以便在发生更改时保存上下文,从而提高(imporve)性能(performance)。
注意:当将模型层分解(factoring)为自己的框架时,
NSPersistentContainer子类(subclass)在自己的包(bundle)中定位(locates)模型文件。
手动(manually)设置Core Data栈
NSPersistentContainer 支持iOS 10.0+ 以及 macOS 10.12+,如果需要**部署(deploying)到较早(earlier)版本的系统,你需要手动(manually)实例化(instantiate)**一个NSManagedObjectModel、一个NSPersistentStoreCoordinator以及至少一个NSManagedObjectContext。
创建一个托管对象模型
实例化(instantiate)NSManagedObjectModel时,你需要传入(pass in)一个指向(points to) .xcdatamodeld 文件的编译版本(compiled version)URL,这个 .momd 文件通常(typically)是应用程序包(app bundle)的一部分(part of)。
guard let modelURL = Bundle.main.url(forResource: "DataModel",
withExtension: "momd") else {
fatalError("Failed to find data model")
}
guard let mom = NSManagedObjectModel(contentsOf: modelURL) else {
fatalError("Failed to create model from file: \(modelURL)")
}
创建持久化(persistent)存储(store)协调器(coordinator)
接着,向NSPersistentStoreCoordinator初始化器传入(pass)已载入的(loaded)模型,用于创建一个关联的(associated)存储(store)协调器(coordinator)。
let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)
添加一个持久化存储
如果你希望Core Data持久化你的数据模型到硬盘,只需要告诉存储协调器什么时候写入(reside)文件以及怎么格式化(format)。
let dirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last
let fileURL = URL(string: "DataModel.sql", relativeTo: dirURL)
do {
try psc.addPersistentStore(ofType: NSSQLiteStoreType,
configurationName: nil,
at: fileURL, options: nil)
} catch {
fatalError("Error configuring persistent store: \(error)")
}
每种可用的(available)存储类型都有其优点(advantages)和缺点(disadvantages),详情请参考
NSPersistentStoreCoordinator的相关文档说明。
创建一个托管对象上下文
创建一个NSManagedObjectContext对象,并设置存储协调器属性(property)。
let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
moc.persistentStoreCoordinator = psc
应用程序与Core Data的**大部分(bulk of)交互(interaction)都是在这个上下文中进行的。通过引用(reference)将此上下文传递(pass)**给用户界面,详情请查看将持久化容器引用传递给视图控制器。