MagicalRecord dispatch_aync 多线程保存

本文介绍了在使用MagicalRecord时遇到的多线程数据一致性问题,并详细解析了NSManagedObjectContext的工作原理。通过创建PrivateContext并利用MagicalRecord的异步保存机制,确保在子线程中操作数据不会阻塞主线程,实现数据的安全保存。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

废话不多说,直接看问题^_^,我的答案也是自己尝试获得的,一开始就不知道有这个东西,到迷迷糊糊的了解,到有点理解,到能用,这需要过程,当然我的水平不高.之所以写下来是觉得可能有人和我一样也在经历这个学习的过程.给大家一些参考.如果觉得我的方案有问题,请留言.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];

        //省略各个信息赋值......

}];



评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值