performBlockAndWait在iOS 7上使用专用队列死锁的子上下文

performBlockAndWait在iOS 7上使用专用队列死锁的子上下文,第1张

概述我有两个名为importContext和childContext的NSManagedObjectContexts. childContext是importContextand的子节点,它们都是NSPrivateQueueConcurrencyType. 为了避开主线程,我在importContext的队列上做了很多工作.这项工作涉及大量的提取和保存,因此将整个事物包装在importContext的 我有两个名为importContext和childContext的NSManagedobjectContexts. childContext是importContextand的子节点,它们都是nsprivateQueueConcurrencyType.

为了避开主线程,我在importContext的队列上做了很多工作.这项工作涉及大量的提取和保存,因此将整个事物包装在importContext的performBlockAnDWait中是很方便的(它确实需要通过同步 *** 作,因为performBlockAnDWait之后的代码依赖于它的结果).

在这项工作中的某些时候,我可能需要从JSON结果创建新的托管对象.这些JsON值可能无效并且我的验证失败,因此在创建对象后,如果它们不好,我需要能够抛弃它们.这就是childContext的用武之地.我将新对象插入其中,如果它的JsON属性最终没有意义,我就抛弃了childContext.

当我需要保存childContext时出现问题.我希望它有自己的私有队列,与父队列分开.但是,这会导致iOS 7(不是iOS 8)上的死锁.当我在iOS 8模拟器和设备上运行相同的代码时,childContext会在单独​​的线程上创建自己的队列并正确进行保存.

看起来当我运行iOS 7时,childContext正在尝试执行save:在父队列中,但父进程正在等待其子进程导致死锁.在iOS 8中,这不会发生.有谁知道为什么?

这是简化的代码:

-(NSManagedobjectContext *)importContext   {       NSManagedobjectContext* moc = [[NSManagedobjectContext alloc] initWithConcurrencyType:nsprivateQueueConcurrencyType];       moc.persistentStoreCoordinator = [self storeCoordinator];       return moc;   }   -(voID)updateItems:(NSArray*)ItemDescriptions   {      [self.importContext performBlockAnDWait:^{           //get info and update           ...           ...       if(needToCreateNewItem){          NSManagedobjectContext* childContext = [[NSManagedobjectContext alloc] initWithConcurrencyType:nsprivateQueueConcurrencyType];          childContext.parentContext = self.importedContext;          //Insert and create new item           ...          [childContext performBlockAnDWait:^{              ID newObject = [NSEntityDescription insertNewObjectForEntityForname:[self entityname]                                                 inManagedobjectContext:childContext];          }];          ...          // Do something with this object          if([newObject isReadyToSave])              __block NSError* e = nil;              __block BOol saveSucceeded = NO;              [childContext performBlockAnDWait:^{                 saveSucceeded = [childContext save:&e]; // DEADLOCK ON iOS 7!!!!              }];          }          ....       }  }];  }

一个简单的解决方法是将工作保持在一个单独的调度队列(而不是importContext的队列),但我问这个问题的原因是因为我想了解发生这种情况的根本原因.我认为孩子的保存应该只发生在自己的队列中.

更新1

回覆.马库斯的问题:

> updateItems:从 *** 作队列中的NSInvocationoperation调用,因此它不在主队列中.
>在iOS 7上,我可以随时暂停应用程序并查看堆栈,并且托管对象上下文的队列将被死锁:

(lldb) bt* thread #7: tID = 0xed07,0x38546aa8 libsystem_kernel.dylib`semaphore_wait_trap + 8,queue = 'NSManagedobjectContext Queue'frame #0: 0x38546aa8 libsystem_kernel.dylib`semaphore_wait_trap + 8frame #1: 0x385bbbac libsystem_platform.dylib`_os_semaphore_wait + 12frame #2: 0x3848461a libdispatch.dylib`_dispatch_barrIEr_sync_f_slow + 138frame #3: 0x2d4f3df2 CoreData`_perform + 102frame #4: 0x2d4fe1ac CoreData`-[NSManagedobjectContext(_nestedContextSupport) executeRequest:withContext:error:] + 240frame #5: 0x2d492f42 CoreData`-[NSManagedobjectContext save:] + 826  * frame #6: 0x000c1c96 DBDevApp`__69+[DBManagedobject createWithAttributes:inManagedobjectContext:error:]_block_invoke77(.block_descriptor=<unavailable>) + 118 at DBManagedobject.m:117frame #7: 0x2d4f6934 CoreData`developersubmittedBlockToNSManagedobjectContextPerform + 88frame #8: 0x3847e81e libdispatch.dylib`_dispatch_clIEnt_callout + 22frame #9: 0x384847ca libdispatch.dylib`_dispatch_barrIEr_sync_f_invoke + 26frame #10: 0x2d4f6a72 CoreData`-[NSManagedobjectContext performBlockAnDWait:] + 106frame #11: 0x000c1916 DBDevApp`+[DBManagedobject createWithAttributes:inManagedobjectContext:error:](self=0x005c1790,_cmd=0x0054a033,attributes=0x188e    context=0x17500800,error=0x02e68ae8) + 658 at DBManagedobject.m:116frame #12: 0x000fe138 DBDevApp`-[DBAPIController createOrUpdateItems:withIDs:IDKeys:ofClass:amongExistingItems:withFindByIDPredicate:](self=0x17775de0,_cmd=0x0054de   newItemDescriptions=0x188eada0,itemIDs=0x18849580,IDKey=0x0058e290,class=0x005c1790,existingItems=0x1756b560,findByID=0x18849c80) + 2472 at DBAPIController.m:972frame #13: 0x00100ca0 DBDevApp`__39-[DBAPIController updatePatIEntGroups:]_block_invoke(.block_descriptor=0x02e68ce0) + 476 at DBAPIController.m:1198frame #14: 0x2d4f6934 CoreData`developersubmittedBlockToNSManagedobjectContextPerform   frame #15: 0x3847e81e libdispatch.dylib`_dispatch_clIEnt_callout + 22frame #16: 0x384847ca libdispatch.dylib`_dispatch_barrIEr_sync_f_invoke + 26frame #17: 0x2d4f6a72 CoreData`-[NSManagedobjectContext performBlockAnDWait:] + 106frame #18: 0x00100a96 DBDevApp`-[DBAPIController updatePatIEntGroups:](self=0x17775de0,_cmd=0x0054dfcd,groupsArray=0x188eada0) + 214 at DBAPIController.m:1191frame #19: 0x2d721584 CoreFoundation`__invoking___ + 68frame #20: 0x2d66c0da CoreFoundation`-[NSInvocation invoke] + 282frame #21: 0x2e0f3d2c Foundation`-[NSInvocationoperation main] + 112frame #22: 0x2e0515aa Foundation`-[__NSOperationInternal _start:] + 770frame #23: 0x2e0f576c Foundation`__NSOQSchedule_f + 60frame #24: 0x38484f10 libdispatch.dylib`_dispatch_queue_drain$VARIANT$mp + 488frame #25: 0x38484c96 libdispatch.dylib`_dispatch_queue_invoke$VARIANT$mp + 42frame #26: 0x38485a44 libdispatch.dylib`_dispatch_root_queue_drain + 76frame #27: 0x38485d28 libdispatch.dylib`_dispatch_worker_thread2 + 56frame #28: 0x385c0bd2 libsystem_pthread.dylib`_pthread_wqthread + 298

我上面展示的代码是一个简化版本.我创建一个新子上下文的部分位于一个名为DBManagedobject的类中.这是整个堆栈的屏幕截图:

更新2 – 解释DBManagedobject

DBManagedobject是我所有核心数据类的基类.它基本上处理与JsON解析的字典之间的转换.它有3个主要方法:createWithAttributes:inManagedobjectContext:error:,– updateWithAttributes:error:和attributes.

> createWithAttributes:inManagedobjectContext:error ::创建提供的托管对象上下文的子上下文,在子上下文中插入一个新对象,并在该对象上调用updateWithAttributes:error:.如果更新成功(即,我们想要在此对象上设置的所有值都有意义),它将保存子上下文,获取对作为参数作为参数的MOC中的新对象的引用,并返回该引用:

NSManagedobjectContext* childContext = [[NSManagedobjectContext alloc] initWithConcurrencyType:nsprivateQueueConcurrencyType];childContext.parentContext = context;__block ID newObject;[childContext performBlockAnDWait:^{    newObject = [NSEntityDescription insertNewObjectForEntityForname:[self entityname] inManagedobjectContext:childContext];}];if ([newObject updateWithAttributes:attributes error:error]){    NSError* e = nil;    if ([childContext save:&e])    {        ID parentContextObject = [context objectWithID:[(NSManagedobject*)newObject objectID]];        return parentContextObject;    }    else    {         if (error != NulL) {            *error = e;        }        return nil;    }}else    return nil;

> updateWithAttributes:error ::大量将JsON键之间的键转换为我在数据模型中使用的键作为实体上的属性. (即’first_name’变为’firstname’).如果需要,它还格式化JsON值(日期字符串变为NSDates).它还建立了关系.

解决方法 谁在调用-updateItems:?如果它出现在主队列中,那么你就会遇到问题,因为你正在阻止它.

假设情况并非如此,您是否可以从Xcode共享显示截止日期的线程堆栈?特别是扩展了队列并扩展了主队列?

一旦我好好看看那个堆栈,我会更新我的答案.

Quellish是正确的,你没有正确插入孩子.该子MOC上的任何活动都应该在-performBlock:或-performBlockAnDWait:中.我会扩展-performBlockAnDWait:来覆盖对象的整个创建和决策,而不仅仅是保存.

更新1

-createWithAttributes是什么:inManagedobjectContext:error:do?似乎该方法正在做一些不合适的事情.也许试图强制永久ID或什么?

更新2

怀疑,你的-createWithAttributes:inManagedobjectContext:error:是你的问题.当你调用-objectWithID时:你导致一个fetch一直向下触发NSPersistentStoreCoordinator,这反过来会导致锁定.

此外,这种方法没有任何帮助.创建一个上下文只是为了创建一个对象,然后立即在另一个上下文中抓取该对象,这绝对没有价值.一切伤害,没有好处.完全删除它,只需在您实际要使用它的上下文中创建对象.从正在使用的上下文中保存或丢弃它.

别聪明.

总结

以上是内存溢出为你收集整理的performBlockAndWait在iOS 7上使用专用队列死锁的子上下文全部内容,希望文章能够帮你解决performBlockAndWait在iOS 7上使用专用队列死锁的子上下文所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1099833.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-28
下一篇 2022-05-28

发表评论

登录后才能评论

评论列表(0条)

保存