一、简介
Core Data 是苹果官方提供的管理数据层对象的框架,它提供了对象—关系映射(ORM)的功能,即能够将 Objective-C 对象转化成数据,保存在 SQLite 数据库文件中,也能够将保存在数据库中的数据还原成 Objective-C 对象。在此数据操作期间,不需要编写任何 SQL 语句。Core Data 针对对象生命周期,以及持久化的对象图管理(object graph management)中的一些常见问题提供了解决方案。CoreData 的主要任务是负责数据更改的管理、序列化到磁盘、最小化内存占用以及查询数据。
Core Data 比 SQLite 做了更进一步的封装,SQLite 提供了数据的存储模型,并提供了一系列 API,你可以通过 API 读写数据库,去处理想要处理的数据。但是 SQLite 存储的数据和你编写代码中的数据(比如一个类的对象)并没有内置的联系,必须你自己编写代码去一一对应。
而 Core Data 却可以解决一个数据在持久化层和代码层的一一对应关系。也就是说,你处理一个对象的数据后,通过保存接口,它可以自动同步到持久化层里,而不需要你去实现额外的代码。
iOS10 中利用 NSPersistentContainer
iOS10 之前涉及 NSManagedObjectContext
、NSPersistentStoreCoordinator
、NSManagedObjectModel
、NSPersistentStore
这些类。
1.Core Data Stack
说是一个对象的集合,由4个主要对象构成:
- managed object context (NSManagedObjectContext)
- persistent store coordinator (NSPersistentStoreCoordinator)
- managed object model (NSManagedObjectModel)
- persistent container (NSPersistentContainer)
Core Data Stack,就是进行数据增删查改、保存的工作台,Apple 提供这样一个工作台,让你方便进行数据的保存。无需关心实现细节。
2.Persistent Container
NSPersistentContainer
是iOS 10、 macOS 10.12 之后才出现的新类。引入这个新类的目的之一,就是为了简化创建 Core Data Stack 这个工作台的过程。所以,在 iOS10 之前,创建 Core Data Stack 会复杂一些。
而 Persistent Container 也有另一个新类 NSPersistentStoreDescription
,可以利用这个类,进行一些定制化设置,比如自定义存储路径、设置存储数据方式等(Core Data 支持 SQLite、XML、Binary、InMemory 4中方式存储数据)。
备注:iOS10中,如果利用 NSPersistentContainer
创建 Core Data Stack,预设的是 NSSQLiteStoreType
类型。并且默认打开了自动轻量化版本迁移功能(换言之,在 iOS10 之前,需要手动进行相关设置,才能打开版本迁移功能)。
3.Managed Object Context。
可以理解为是一块内存,提供了和 Managed Objects 交互的场所。也称为:The Context 或者 MOC。NSManagedObjectContext
类实例。
备注:对数据进行删除、保存、查询,都要用到 NSManagedObjectContext
类的相关方法。
4.Managed Object Model
直观点,你可以把它理解为就是 Xcode 中后缀为 xcdatamodel
的文件。在这个文件里,你可以通过非代码、可视化的方式,定义对象、对象的属性、对象之间的关系(Core Data 把对象称呼为实体、对象的属性称呼为特性)。
Managed Object Model 就是 Core Data 中用于描述实体、实体特性、实体间关系的一套方案。
它是 NSManagenObjectModel
的类实例(也可以通过纯代码实现 .xcdatamodel
文件的内容)。
Entity - 实体
NSEntityDescription
类实例,用于定义一个对象。一个实体,最少要有名字和类名(如果没有设置类名,默认是 NSManagedObject
类)。
Attribute - 特性
实体特性 NSAttributeDescription
类实例。就是 Entity 的特性,对应 App 中的创建类时的属性。
Relationship - 关系
实体关系 NSRelationshipDescription
类实例。用于描述 Entity 之间的关系。
5.Managed Object。
就是需要保存的数据,是 NSManagenObject
类实例。(对应 App 中的对象)
就我的理解,Managed Object 和上面提到的 Entity,本质上是同一个东西,就是你的数据对象,只不过是在可视化操作和纯代码操作中的不同称谓。
6.Persistent Store Coordinator
协调 Context 和 Persistent Store 的一个角色。NSPersistentStoreCoordinator
类实例。
如果只是对数据进行简单的增删查改,我们并不需要接触到这个类。
7.Persistent Store
可以理解为保存数据的地方。用于设置保存数据的方式、以及保存的路径等。(保存数据的方式指 SQLite、XML、Binary、InMemory 4种)。NSPersistentStore
类实例。也称为 The Store 或者 Database。
在 iOS10 之前,如果需要支持版本迁移功能,需要在创建 NSPersistentStore
类实例时,传入相应的 options
参数。而在 iOS10 中,则会自动打开版本迁移功能,并默认设置数据类型为 NSSQLiteStoreType
。
版本迁移,假如修改了数据模型(比如修改了 . xcdatamodel
文件:增加了实体,增加了特性等等�),为了防止使用者在更新 App 后,由于数据模型不一致导致崩溃,需要进行一定的处理,这个处理叫版本迁移。
二、使用
1.初始化 Core Data Stack
不过由于 iOS10 新引进了 NSPersistentContainer
类,然后新建项目又可以选择勾选 Core Data 与否。所以情况变得稍稍有点复杂。
这里分三种情况:1、在既有项目(只需支持iOS10)初始化 Core Data Stack;2、在既有项目(需兼容iOS8、9、10等系统)初始化 Core Data Stack;3、新建项目时直接勾选了 Core Data。
(1)在既有项目添加 Core Data 功能(只需支持iOS10)
// 我们先声明了一个NSPersistentContainer类型的属性:persistentContainer,在适合的时间调用initWithName:对其初始化
// 这里的Name参数,需要和后续创建的.xcdatamodeld模型文件名称一致。
_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"Model"];
// 调用loadPersistentStoresWithCompletionHandler:方法,完成Core Data Stack的最中初始化。
// 如果不能初始化成功,在Block回调中打印错误,方便调试
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription * _Nonnull description, NSError * _Nullable error) {
if (error != nil) {
NSLog(@"Fail to load Core Data Stack : %@", error);
abort();
}
else {
...
}
}];
分为两步:
- 初始化
NSPersistentContainer
对象 - 调用
NSPersistentContainer
的loadPersistentStoresWithCompletionHandler:
完成初始化
(2)在既有项目初始化 Core Data Stack(需兼容iOS8、9、10等系统)
- (instancetype)init
{
self = [super init];
if (self) {
NSInteger majorVersion = [NSProcessInfo processInfo].operatingSystemVersion.majorVersion;
if (majorVersion < 10) {
// iOS10以下的系统, 用旧有的方法初始化Core Data Stack
[self initializeCoreDataLessThaniOS10];
}
else {
// iOS10的系统, 用新的方法(详见上面介绍的情况1)
[self initializeCoreData];
}
}
return self;
}
- (void)initializeCoreDataLessThaniOS10 {
// Get managed object model(拿到模型文件,也就是.xcdatamodeld文件(我们会在初始化完Core data Stack后创建))
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"momd"];
NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
NSAssert(mom != nil, @"Error initalizing Managed Object Model");
// Create persistent store coordinator(创建NSPersistentStoreCoordinator对象(需要传入上述创建的NSManagedObjectModel对象))
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
// Creat managed object context(创建NSManagedObjectContext对象(_context是声明在.h文件的属性——因为其他类也要用到这个属性))
_context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
// assgin persistent store coordinator(赋值persistentStoreCoordinator)
_context.persistentStoreCoordinator = psc;
// Create .sqlite file(在沙盒中创建.sqlite文件)
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *documentsURL = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *storeURL = [documentsURL URLByAppendingPathComponent:@"DataModel.sqlite"];
// Create persistent store(异步创建NSPersistentStore并add到NSPersistentStoreCoordinator对象中,作用是设置保存的数据类型(NSSQLiteStoreType)、保存路径、是否支持版本迁移等)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 用于支持版本迁移的参数
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSError *error = nil;
NSPersistentStoreCoordinator *psc = _context.persistentStoreCoordinator;
// 备注,如果options参数传nil,表示不支持版本迁移
NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:options
error:&error];
NSAssert(store != nil, @"Error initializing PSC: %@\n%@", [error localizedDescription], [error userInfo]);
});
}
(3)创建项目直接勾选 Use Core Data
项目模版会在 AppDelegate 类中直接帮你初始化好 Core Data Stack。
2.创建 managed object model
选择 Core Data 栏目下的 Data Model ,就可以创建一个 .xcdatamodeld
模型文件。
自己创建的默认系统提供的命名为 Model.xcdatamodeld
。
添加实体、实体的特性、关系:
(1)Entity
当在 Xcode 中点击 Model.xcdatamodeld
时,会看到编辑视图 Add Entity
。
如果把数据模型文件比作数据库中的“库”,那么 Entity 就相当于库里的实体。
假设我这个数据模型是用来存放图书馆信息的,那么很自然的,我会想建立一个叫 Book 的 Entity。
(2) Attributes
当建立一个名为 Book 的 Entity 时,会看到视图中有栏写着 Attributes,我们知道,当我们定义一本书时,自然要定义书名,书的编码等信息。这部分信息叫 Attributes,即书的属性。
(3) Relationship
在我们使用 Entity 编辑时,除了看到了Attributes 一栏,还看到下面有 Relationships 一栏
在 Reader 的 Relationship 下点击 + 号键。然后在Relationship 栏的名字上填 borrow,表示读者和书的关系是“借阅”,在 Destination 栏选择 Book,这样,读者和书籍的关系就确立了。
对于第三栏,Inverse,需要创建 Book 的 Relationship 后在关联。
选择 Book 的一栏,在 Relationship 下添加新的 borrowBy,Destination 是 Reader,这时候点击 Inverse 一栏,会发现弹出了 borrow,直接点上。
那么在 Reader 的 Relationship 中,我们会发现 Inverse 一栏会自动补齐为 borrowBy。因为电脑这时候已经完全理解了双方的关系,自动做了补齐。
一对一和一对多 - to one和to many
我们建立 Reader 和 Book 之间的联系的时候,发现他们的联系逻辑之间还漏了一个环节。
假设一本书被一个读者借走了,它就不能被另一个读者借走,而当一个读者借书时,却可以借很多本书。
也就是说,一本书只能对应一个读者,而一个读者却可以对应多本书。
这就是 一对一 → to one 和 一对多 → to many 。
3.创建 NSManagedObject
子类
(1)方法1
直接 Command + N 创建一个新类,继承 NSManagedObject
类,然后定义的属性和模型文件中的一致。
(2)方法2
选中对应的实体,然后 Editor > Create NSManagedObject Subclass...,系统自动生成 NSManagedObject
子类。
这种方法,如果有一对多的关系,会生成 2 个Category(Core Data生成的 NSManagedObject
子类,都是以 Category 形式存在的)
CoreDataProperties:生成实体中 Attributes 对应的属性。Relationships 也会生成对应的属性:一对多关系是 NSSet/NSOrderSet
类型属性(本质是个集合),一对一关系则是非集合的对象类型属性。
CoreDataGeneratedAccessors 其实就是一系列增加、删除 NSOrderSet/NSSet
里元素的方法。(如果没有对多关系,不会有这个 Category)
网友评论