我有两个名为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 + 8
frame #1: 0x385bbbac libsystem_platform.dylib`_os_semaphore_wait + 12
frame #2: 0x3848461a libdispatch.dylib`_dispatch_barrier_sync_f_slow + 138
frame #3: 0x2d4f3df2 CoreData`_perform + 102
frame #4: 0x2d4fe1ac CoreData`-[NSManagedobjectContext(_nestedContextSupport) executeRequest:withContext:error:] + 240
frame #5: 0x2d492f42 CoreData`-[NSManagedobjectContext save:] + 826
  * frame #6: 0x000c1c96 DBDevApp`__69+[DBManagedobject createWithAttributes:inManagedobjectContext:error:]_block_invoke77(.block_descriptor=<unavailable>) + 118 at DBManagedobject.m:117
frame #7: 0x2d4f6934 CoreData`developerSubmittedBlockToNSManagedobjectContextPerform + 88
frame #8: 0x3847e81e libdispatch.dylib`_dispatch_client_callout + 22
frame #9: 0x384847ca libdispatch.dylib`_dispatch_barrier_sync_f_invoke + 26
frame #10: 0x2d4f6a72 CoreData`-[NSManagedobjectContext performBlockAndWait:] + 106
frame #11: 0x000c1916 DBDevApp`+[DBManagedobject createWithAttributes:inManagedobjectContext:error:](self=0x005c1790,_cmd=0x0054a033,attributes=0x188e    context=0x17500800,error=0x02e68ae8) + 658 at DBManagedobject.m:116
frame #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:972
frame #13: 0x00100ca0 DBDevApp`__39-[DBAPIController updatePatientGroups:]_block_invoke(.block_descriptor=0x02e68ce0) + 476 at DBAPIController.m:1198
frame #14: 0x2d4f6934 CoreData`developerSubmittedBlockToNSManagedobjectContextPerform   
frame #15: 0x3847e81e libdispatch.dylib`_dispatch_client_callout + 22
frame #16: 0x384847ca libdispatch.dylib`_dispatch_barrier_sync_f_invoke + 26
frame #17: 0x2d4f6a72 CoreData`-[NSManagedobjectContext performBlockAndWait:] + 106
frame #18: 0x00100a96 DBDevApp`-[DBAPIController updatePatientGroups:](self=0x17775de0,_cmd=0x0054dfcd,groupsArray=0x188eada0) + 214 at DBAPIController.m:1191
frame #19: 0x2d721584 CoreFoundation`__invoking___ + 68
frame #20: 0x2d66c0da CoreFoundation`-[NSInvocation invoke] + 282
frame #21: 0x2e0f3d2c Foundation`-[NSInvocationoperation main] + 112
frame #22: 0x2e0515aa Foundation`-[__NSOperationInternal _start:] + 770
frame #23: 0x2e0f576c Foundation`__NSOQSchedule_f + 60
frame #24: 0x38484f10 libdispatch.dylib`_dispatch_queue_drain$VARIANT$mp + 488
frame #25: 0x38484c96 libdispatch.dylib`_dispatch_queue_invoke$VARIANT$mp + 42
frame #26: 0x38485a44 libdispatch.dylib`_dispatch_root_queue_drain + 76
frame #27: 0x38485d28 libdispatch.dylib`_dispatch_worker_thread2 + 56
frame #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上使用专用队列死锁的子上下文的更多相关文章

  1. ios – 使用watchOS 2在Apple Watch上渲染折线图

    我正在尝试使用watchOS2在AppleWatch上渲染线条/步骤图.与iOS9不同,watchOS2不支持Quartz.它只支持CoreGraphics.我尝试编写一些代码来绘制折线图但我得到一个错误“CGContextRestoreGState:无效的上下文0x0.这是一个严重的错误.这个应用程序,或它使用的库,正在使用无效的上下文,从而有助于整体系统稳定性和可靠性降低.这个通知是礼貌的:请

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

    如果它出现在主队列中,那么你就会遇到问题,因为你正在阻止它.假设情况并非如此,您是否可以从Xcode共享显示截止日期的线程堆栈?一旦我好好看看那个堆栈,我会更新我的答案.Quellish是正确的,你没有正确插入孩子.该子MOC上的任何活动都应该在-performBlock:或-performBlockAndWait:中.我会扩展-performBlockAndWait:来覆盖对象的整个创建和决策,而不仅仅是保存.更新1-createWithAttributes是什么:inManagedobjectCont

  3. ios – 合并子上下文时的NSObjectInaccessbileExceptions

    我尝试手动重现,但失败了.是否有其他可能发生这种情况的情况,是否有处理此类问题的提示?解决方法在创建子上下文时,您可以尝试使用以下行:

  4. ios – CGContextClear警告

    解决方法我想说它肯定与CGContextClear有关.它保留了你在记忆中的所有东西.虽然您的上下文未被清除或释放,但它会将该上下文中定义的元素保留在内存中.您使用的是哪个版本的iOS?

  5. ios – 设置NSDataDetector的上下文日期

    假设今天是2014年1月20日.如果我使用NSDataDetector从“明天下午4点”字符串中提取日期,我将得到2014-01-21T16:00.大.但是,假设我希望NSDataDetector假装当前日期是2014年1月14日.这样,当我解析“明天下午4点”时,我将得到2014-01-15T16:00.如果我在设备上更改系统时间,我会得到我想要的.但是,有没有办法以编程方式指定它?

  6. 你将NSArrayController的托管对象上下文绑定到Xcode 4中的是什么?

    实际上,我对绑定一切都有同样的问题;我的UI对象都不适用于我的模型.我唯一能想到的是File的Owner和NSArrayController之间的连接出了问题.我此时还没有编写任何代码,因为我理解我不应该仅仅链接UI字段和核心数据.它是不同的因为我使用的是基于文档的应用程序?“不使用核心数据”的答案不会有成效;我知道我可以回到常规数据对象上.如果可能的话,我想在核心数据的背景下解决这个问题.TIA!

  7. ios – UIApplication.delegate必须仅在主线程中使用[复制]

    我应该在主调度中的viewControllers中声明这些)变量位置声明定义了它的范围.您需要确定这些变量的范围.您可以将它们声明为项目或应用程序级别(全局),类级别或特定此功能级别.如果要在其他ViewControllers中使用这些变量,则使用公共/开放/内部访问控制将其声明为全局或类级别.

  8. ios – 核心数据 – 保存上下文后撤消更改

    但是,实际情况并非如此!即使我使用托管对象上的更改保存上下文,以下-undo调用仍将成功撤消更改.这不是针对文档中陈述的内容吗?也许我做错了什么?

  9. ios – 我可以安全地在@try catch块中包装’CoreData无法解决错误’错误

    )是的,我偶尔会得到’CoreData无法完成故障’的错误.在我的特定应用程序中,这通常发生在一种“数据绑定”过程中,因此我可以安全地丢弃故障对象并继续前进.我想通过在@try-catch块中包装数据绑定的循环内部并且只跳过我得到CoreData错误的行来完成此操作.我可以使用CoreData安全地执行此操作吗?

  10. ios – 你可以在它的上下文的performBlock之外使用NSManagedObject吗?

    或者是否有背景魔法在使用吸气剂的情况下帮助保护我?(或者是安装者,虽然这看起来像个坏主意……)解决方法NSManagedobject不应该在其managedobjectContexts线程/队列之外使用.CoreData不保证对对象的安全读取访问.要访问“私有队列”上下文所拥有的对象,请始终使用[contextperformBlock:…

随机推荐

  1. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. iOS – genstrings:无法连接到输出目录en.lproj

    使用我桌面上的项目文件夹,我启动终端输入:cd然后将我的项目文件夹拖到终端,它给了我路径.然后我将这行代码粘贴到终端中找.-name*.m|xargsgenstrings-oen.lproj我在终端中收到此错误消息:genstrings:无法连接到输出目录en.lproj它多次打印这行,然后说我的项目是一个目录的路径?没有.strings文件.对我做错了什么的想法?

  3. iOS 7 UIButtonBarItem图像没有色调

    如何确保按钮图标采用全局色调?解决方法只是想将其转换为根注释,以便为“回答”复选标记提供更好的上下文,并提供更好的格式.我能想出这个!

  4. ios – 在自定义相机层的AVFoundation中自动对焦和自动曝光

    为AVFoundation定制图层相机创建精确的自动对焦和曝光的最佳方法是什么?

  5. ios – Xcode找不到Alamofire,错误:没有这样的模块’Alamofire’

    我正在尝试按照github(https://github.com/Alamofire/Alamofire#cocoapods)指令将Alamofire包含在我的Swift项目中.我创建了一个新项目,导航到项目目录并运行此命令sudogeminstallcocoapods.然后我面临以下错误:搜索后我设法通过运行此命令安装cocoapodssudogeminstall-n/usr/local/bin

  6. ios – 在没有iPhone6s或更新的情况下测试ARKit

    我在决定下载Xcode9之前.我想玩新的框架–ARKit.我知道要用ARKit运行app我需要一个带有A9芯片或更新版本的设备.不幸的是我有一个较旧的.我的问题是已经下载了新Xcode的人.在我的情况下有可能运行ARKit应用程序吗?那个或其他任何模拟器?任何想法或我将不得不购买新设备?解决方法任何iOS11设备都可以使用ARKit,但是具有高质量AR体验的全球跟踪功能需要使用A9或更高版本处理器的设备.使用iOS11测试版更新您的设备是必要的.

  7. 将iOS应用移植到Android

    我们制作了一个具有2000个目标c类的退出大型iOS应用程序.我想知道有一个最佳实践指南将其移植到Android?此外,由于我们的应用程序大量使用UINavigation和UIView控制器,我想知道在Android上有类似的模型和实现.谢谢到目前为止,guenter解决方法老实说,我认为你正在计划的只是制作难以维护的糟糕代码.我意识到这听起来像很多工作,但从长远来看它会更容易,我只是将应用程序的概念“移植”到android并从头开始编写.

  8. ios – 在Swift中覆盖Objective C类方法

    我是Swift的初学者,我正在尝试在Swift项目中使用JSONModel.我想从JSONModel覆盖方法keyMapper,但我没有找到如何覆盖模型类中的Objective-C类方法.该方法的签名是:我怎样才能做到这一点?解决方法您可以像覆盖实例方法一样执行此操作,但使用class关键字除外:

  9. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  10. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

返回
顶部