CoreData的构成:
(1)NSManagedObjectContext 被管理者对象上下文,相当于一个未存储的临时数据库,我们存储或者查询都是通过这个对象来的。
(2)NSManagedObjectModel 被管理对象模型,可以简单的理解为可视化建模文件,可视化建模中是Entity自动生成model 方便让文件存储助理来进行管理。
(3)NSPersistentStoreCoordinator 文件存储助理,相当于数据库的链接器,它是CpreData的核心负责链接所有的模块,包括真实的存储文件。
(4)NSManagedObject 被管理的数据记录, 相当于数据库中的表格记录。
(5)NSFetchRequest 获取数据的请求,相当于SQL语句。
(6)NSEntityDescription 实体结构,相当于表结构。
(7)后缀为.xcdatamodeld的包 里面是.xcodemodel文件 用数据模型编辑器编译。编译后为.momd或.mom文件。
一些细节:
1、NSManagedObjectContext创建时apple推荐使用参数NSPrivateQueueConcurrencyType或NSMainQueueConcurrencyType,二者区别如下:
使用NSMainQueueConcurrencyType初始化时,block将会在主线程中执行
[_context performBlock:^(){
[_context save:nil];
}];
使用NSPrivateQueueConcurrencyType初始化时,block将会在新子线程中执行,此中情况下涉及到更新UI的操作需要在主线程中调用,因此可以改进如下:
[_context performBlock:^(){
[_context save:nil];
dispatch_async(dispatch_get_main_queue(), ^{
[_tableView reloadData];
[self scrollToBottom];
});
}];
2、MOC不是线程安全的,多个线程不能使用同一个,因此多线程使用MOC可以使用parent-child方法解决,每个子线程有一个MOC,主线程有一个MOC,主线程MOC是子线程MOC的parentContext。
例子如下:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(){
NSManagedObjectContext *childcontext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
childcontext.parentContext = _context;
[childcontext performBlock:^(){
Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:childcontext];
person.name = [NSString stringWithFormat:@"json%i",count++];
person.age = [NSNumber numberWithUnsignedInt:20];
person.timestamp = [NSDate date];
NSManagedObjectID *personid = person.objectID;
[childcontext save:nil];
[_context performBlock:^(){
[_context save:nil];
[_contextWrite performBlockAndWait:^(){
if ([_contextWrite hasChanges])
{
[_contextWrite save:nil];
}
}];
dispatch_async(dispatch_get_main_queue(), ^(){
[self.dataList addObject:[_contextWrite objectWithID:personid]];
[_tableView reloadData];
[self scrollToBottom];
});
}];
}];
});
以上parentcontext(main)<---childcontext(private)结构就可以解决大多数问题了,因为数据库的复杂操作往往来自于查询,尤其那些正则匹配、模糊查找,而将这些费时的操作放入childcontext中有多线程异步处理,可以不阻塞主线程。
上面的结构相当于将写入数据库的操作放在主线程中执行,因此对于大量写入数据库的情况是不适用的。而此时则可以使用三层结构解决:grandcontext(private)<---parentcontext(main)<---childcontext(private),其中childcontext负责数据处理查询,parentcontext用于同步操作、解决线程安全问题,grandcontext则用于写入操作。
3、多线程之间是不允许传递NSManagedObject的,但是可以通过传递NSManagedObjectID来解决。