废话不多说,直接看问题^_^,我的答案也是自己尝试获得的,一开始就不知道有这个东西,到迷迷糊糊的了解,到有点理解,到能用,这需要过程,当然我的水平不高.之所以写下来是觉得可能有人和我一样也在经历这个学习的过程.给大家一些参考.如果觉得我的方案有问题,请留言.O(∩_∩)O~
项目中遇到的问题:因为要一次性保存很多数据,所以用到了多线程,我用的是GCD,也就是
dispatch_async(dispatch_get_global_queue(0, 0), ^{
}
在线程中做的操作如下:
DataModel *model = [self createModel:fileType item:item];
model.filePath = [NSString stringWithFormat:@"/photoLibrary/%@",model.fileName];
model.status = @(E_Done);
[[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
这样做的后果就是:并没有存储成功,或者有可能暂时可以取到数据,杀掉程序后再次启动,一切都没改变,数据跑哪了?</span>
这种写法导致了多线程数据不一致的问题.此时我们需要理解一下NSManagedObjectContext,它是何方神圣?其实说白了就是一个操作数据库的封装接口,是个接头人,我有要保存的数据,你就准备好就行了,由它来保存就行.但是我们要知道:
NSManagedObjectContext(被管理的数据上下文)操作实际内容(操作持久层)
什么意思,context是一个上下文,它做的操作只有在他自己的空间感知,也就是创建他的线程感知.在MagicalRecord中,使用如下方式
[NSManagedObjectContext MR_defaultContext] 返回值其实就是主线程中创建的context.
你如果在其他线程中调用它返回的context来曾删改数据,主线程是不知道的.你在这边哼哼哈嘿的舞刀弄枪,别人压根不知道.所以说增删改都不会成功.
那么这种情况我们该怎么办呢?
思路如下:persistentStoreCoordinator<-backgroundContext<-mainContext<-privateContext
子线程中需要创建一个PrivateContext.
NSManagedObjectContext *privateContext= [NSManagedObjectContext MR_contextWithParent:[NSManagedObjectContext MR_defaultContext]];
privateContext的父context是mainContext,这样子线程中做的操作交给主线程来做.那有人会说,这样还是要调用主线程,岂不是还会阻塞主线程吗?这个MagicalRecord已经替我们考虑了,看下面NSManagedObjectContext + MagicalRecord.h文件中
+(void) MR_initializeDefaultContextWithCoordinator:(NSPersistentStoreCoordinator *)coordinator;
{
NSAssert(coordinator, @"Provided coordinator cannot be nil!");
if (MagicalRecordDefaultContext == nil)
{
NSManagedObjectContext *rootContext = [self MR_contextWithStoreCoordinator:coordinator];
[self MR_setRootSavingContext:rootContext];
NSManagedObjectContext *defaultContext = [self MR_newMainQueueContext];
[self MR_setDefaultContext:defaultContext];
[defaultContext setParentContext:rootContext];}
上面这段代码最重要的地方是:
[defaultContext setParentContext:rootContext];
主线程的context的父context是另一个privateContext,这样主线程的任务就交给了另一个子线程的context完成,主线程就不会阻塞了.具体代码可以去MagicalRecord的源文件中查找.
下面就是我现在使用的方式:^_^ (如有问题,欢迎指正)
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSManagedObjectContext *privateContext= [NSManagedObjectContext MR_contextWithParent:[NSManagedObjectContext MR_defaultContext]];
DataModel *model = [DataModel MR_createEntityInContext:privateContext]
model.filePath = [NSString stringWithFormat:@"/photoLibrary/%@",model.fileName];
model.status = @(E_Done);
[privateContext MR_saveToPersistentStoreAndWait];
还可以用block的形式:
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
HistoryDataModel *histItem = nil;
histItem = [HistoryDataModel MR_createEntityInContext:localContext];
//省略各个信息赋值......
}];