CoreData概念
CoreData是一种OR-Mapping思想,O代表对象Object,R代表Relationship,Mapping代表映射,总结起来就是对象关系映射,其实就是把对象的属性和表中的字段自动映射。CoreData本质还是数据库,只不过它具有面相对象的特性,不关注二维表结构,是纯对象的数据库操作方式。
初始化Core Data Stack
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)
由于iOS10
引进了NSPersistentContainer
,如果单单只支持iOS10
系统,初始化Core Data Stack
相比以前简单很多。
// 我们先声明了一个NSPersistentContainer类型的属性:persistentContainer,在适合的时间调用initWithName:对其初始化
// 这里的Name参数,需要和后续创建的.xcdatamodeld模型文件名称一致。
_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"MoveBand"];
// 调用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 {
...
}
}];
就两步:
(1) 初始化NSPersistentContainer
对象;
(2) 调用NSPersistentContainer
的loadPersistentStoresWithCompletionHandler:
完成初始化。
-
情况2:在既有项目初始化
Core Data Stack
(需兼容iOS8、9、10
等系统)
因为NSPersistentContainer
不兼容iOS10
之前的系统。所以,如果你已经用了NSPersistentContainer
初始化了Core Data Stack
,但同时也要兼容iOS8、9
等系统,就需要在代码中检查,如果是旧的系统,就需要用旧的方法初始化Core Data Stack
了。示例如下:
- (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:@"MoveBand" 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:直接勾选Core Data
创建项目时,如果直接勾选Core Data
复选框,项目模版会在AppDelegate
类中直接帮你初始化好Core Data Stack
,自动创建和上面情况1类似的代码(Xcode8)
在AppDelegate.h文件
#import <UIKit/UIKit.h>
// 导入了CoreData框架
#import <CoreData/CoreData.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
// 在.h文件声明一个NSPersistentContainer类型的属性(为了让其他类可以调用)
@property (readonly, strong) NSPersistentContainer *persistentContainer;
// 声明了一个保存数据的方法
- (void)saveContext;
@end
在AppDelegate.m文件
@implementation AppDelegate
#pragma mark - Core Data stack
@synthesize persistentContainer = _persistentContainer;
- (NSPersistentContainer *)persistentContainer {
@synchronized (self) {
if (_persistentContainer == nil) {
// 实例化NSPersistentContainer对象。
// 注意:参数传入的名称,就是.xcdatamodeld文件名称(两者需要一直)(勾选Core Data后,会自动创建一个.xcdatamodeld文件)
_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"CoreDataTestUseCoreData"];
// 加载persistent stores,实现最终的Core Data stack的创建
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
// 如果有错误,打印出来
if (error != nil) {
NSLog(@"Unresolved error %@, %@", error, error.userInfo);
abort();
}
}];
}
}
return _persistentContainer;
}
#pragma mark - Core Data Saving support
- (void)saveContext {
// 注意这句,NSManagedObjectContext对象,是通过上面创建的NSPersistentContainer对象的属性viewContext获取的,无需自己初始化(iOS10之前要自己初始化)
NSManagedObjectContext *context = self.persistentContainer.viewContext;
NSError *error = nil;
// 保存数据,直接用的是NSManagedObjectContext的save:方法,很简单。
if ([context hasChanges] && ![context save:&error]) {
NSLog(@"Unresolved error %@, %@", error, error.userInfo);
abort();
}
}
系统帮我们创建了一个NSPersistentContainer
实例,以及一个saveContext
方法。(并且已经帮我们创建了.xcdatamodeld
模型文件)