【问题标题】:EXC_BAD_ACCESS when trying to save from child managed context to parent尝试从子托管上下文保存到父上下文时的 EXC_BAD_ACCESS
【发布时间】:2013-07-19 22:05:58
【问题描述】:

我有一个正在杀死我的 EXC_BAD_ACCESS。我看不出它可能来自哪里。

ARC 代码。 SymptomRating 是一个托管对象,当然:

__block DPLSymptomRating *rating;
self.editMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];  // retained: strong

NSManagedObjectContext *moc = self.editMOC; //editSymptom.managedObjectContext;

[moc performBlockAndWait:^{
    NSError __autoreleasing *error = nil;
    moc.parentContext = DPLPersonalHxDataStore.shared.managedObjectContext;

    rating = [NSEntityDescription insertNewObjectForEntityForName:@"SymptomRating" inManagedObjectContext:moc];
    [moc assignObject:rating toPersistentStore:[NSPersistentStore MR_defaultPersistentStore]];

    rating.ratingCode = @101;
    rating.symptomCode = 1;
    rating.displayName = @"debug";
    NSAssert(rating!=nil, @"Cannot edit nil rating");
    NSAssert(rating.managedObjectContext==moc, @"");
    NSLog(@"validates for insert: %@", [rating validateForInsert:&error]?@"true":@"false");
    NSAssert(error==nil,@"");
    NSLog(@"inserted objects: %@", moc.insertedObjects);    // 1 object, from above
    NSLog(@"updated objects: %@", moc.updatedObjects);      // empty
    NSLog(@"deleted objects: %@", moc.deletedObjects);      // empty
    [moc save:&error];   // -->FAIL: EXC_BAD_ACCESS (code=2, address=0x2)
    NSLog(@"can we get here?");  // NOPE
    NSAssert(error==nil, @"");
}];

无论并发类型是 Main 还是 Private,以及使用或不使用 -performBlock: 或 -performBlockAndWait:,这都会崩溃并出现相同的错误

我有 NSZombieEnabled(我想 -- 不知道如何验证它是否真的有效)。

回溯:

frame #0: 0x019c0098 libobjc.A.dylib`objc_msgSend + 12
frame #1: 0x0087e5e0 CoreData`_PFObjectIDFastHash64 + 96
frame #2: 0x01fb48d0 CoreFoundation`__CFDictionaryHashKey + 32
frame #3: 0x01f0a114 CoreFoundation`CFBasicHashFindBucket + 1572
frame #4: 0x01f09ad5 CoreFoundation`CFDictionaryGetValue + 133
frame #5: 0x0088cde8 CoreData`-[NSPersistentStoreCache incrementRefCountForObjectID:] + 40
frame #6: 0x0088cd74 CoreData`-[NSSQLCore managedObjectContextDidRegisterObjectsWithIDs:] + 228
frame #7: 0x009528aa CoreData`-[NSPersistentStoreCoordinator(_NSInternalMethods) _informAffectedStoresOfInterestByChildContextInObjectsWithObjectIDs:withSelector:] + 122
frame #8: 0x0088cc7f CoreData`-[NSPersistentStoreCoordinator(_NSInternalMethods) managedObjectContextDidRegisterObjectsWithIDs:] + 47
frame #9: 0x008bd9e9 CoreData`__-[NSManagedObjectContext(_NestedContextSupport) managedObjectContextDidRegisterObjectsWithIDs:]_block_invoke_1 + 73
frame #10: 0x008bce41 CoreData`internalBlockToNSManagedObjectContextPerform + 17
frame #11: 0x01de5953 libdispatch.dylib`_dispatch_barrier_sync_f_invoke + 61
frame #12: 0x01de5e00 libdispatch.dylib`dispatch_barrier_sync_f + 62
frame #13: 0x008bcde5 CoreData`_perform + 117
frame #14: 0x008bd999 CoreData`-[NSManagedObjectContext(_NestedContextSupport) managedObjectContextDidRegisterObjectsWithIDs:] + 73
frame #15: 0x008bd9e9 CoreData`__-[NSManagedObjectContext(_NestedContextSupport) managedObjectContextDidRegisterObjectsWithIDs:]_block_invoke_1 + 73
frame #16: 0x008bcdc4 CoreData`_perform + 84
frame #17: 0x008bd999 CoreData`-[NSManagedObjectContext(_NestedContextSupport) managedObjectContextDidRegisterObjectsWithIDs:] + 73
frame #18: 0x008ac672 CoreData`-[NSManagedObjectContext(_NSInternalAdditions) _informParentStore:ofInterestInObjects:] + 274
frame #19: 0x008991e8 CoreData`-[NSManagedObjectContext save:] + 536
frame #20: 0x000a06fc MyApp`__53-[DPLNotesViewController editRatingForIndexPath:new:]_block_invoke(.block_descriptor=0xbfffe260) + 1836 at DPLNotesViewController.m:270
frame #21: 0x008bcaf3 CoreData`developerSubmittedBlockToNSManagedObjectContextPerform + 99
frame #22: 0x01de5953 libdispatch.dylib`_dispatch_barrier_sync_f_invoke + 61
frame #23: 0x01de5e00 libdispatch.dylib`dispatch_barrier_sync_f + 62
frame #24: 0x008bca48 CoreData`-[NSManagedObjectContext performBlockAndWait:] + 136
frame #25: 0x0009fe61 MyApp`-[DPLNotesViewController editRatingForIndexPath:new:](self=0x0a367eb0, _cmd=0x0010fb59, indexPath=0x083f9200, new='\x01') + 465 at DPLNotesViewController.m:251
frame #26: 0x0009f786 MyApp`-[DPLNotesViewController tableView:didSelectRowAtIndexPath:](self=0x0a367eb0, _cmd=0x02ba0ff6, tableView=0x08c69a00, indexPath=0x083f9200) + 150 at DPLNotesViewController.m:195
frame #27: 0x00bad71d UIKit`-[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1164
frame #28: 0x00bad952 UIKit`-[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 201
frame #29: 0x0143586d Foundation`__NSFireDelayedPerform + 389
frame #30: 0x01fc6966 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 22
frame #31: 0x01fc6407 CoreFoundation`__CFRunLoopDoTimer + 551
frame #32: 0x01f297c0 CoreFoundation`__CFRunLoopRun + 1888
frame #33: 0x01f28db4 CoreFoundation`CFRunLoopRunSpecific + 212
frame #34: 0x01f28ccb CoreFoundation`CFRunLoopRunInMode + 123
frame #35: 0x021ac879 GraphicsServices`GSEventRunModal + 207
frame #36: 0x021ac93e GraphicsServices`GSEventRun + 114
frame #37: 0x00b1da9b UIKit`UIApplicationMain + 1175

我还能尝试什么?救命!

【问题讨论】:

  • 您是否尝试过使用“直接”存储上下文(没有父上下文,但只有持久存储)?
  • 是的,如果我只是直接使用父上下文,它就可以正常工作。
  • 您是否尝试过删除assignObject:toPersistentStore: 电话?
  • DPLPersonalHxDataStore.shared.managedObjectContext的并发类型是什么?您是否尝试在父上下文线程中设置父上下文(确保父上下文在适当的线程上初始化)?
  • 如果您的只读存储和写入存储都使用相同的配置,请为每个配置创建一个唯一的配置。这就是告诉 CoreData 在哪些存储中保存东西的原因。您不应该直接调用 assignObject:toPersistentStore:。

标签: core-data automatic-ref-counting exc-bad-access


【解决方案1】:

这个问题原来是一个 iOS 5 错误,其中父上下文显然无法看到他们孩子的新关系。强制 Core Data 在尝试保存之前获取永久对象 ID 可修复问题,如下所示:

[moc obtainPermanentIDsForObjects:@[rating] error:&error];
[moc save:&error];   // --> WORKS NOW

【讨论】:

  • 我认为你明白了关系的重点,但这不仅仅是 ios5 中的错误,我在 ios6 中也看到过这个问题,也许是 7。在 ios6 中,我在建立关系时遇到错误,而不是保存时。
  • 我在 iOS 6(但不是 iOS 7)上遇到了同样的问题。我在 iOS 7 上看到的_PFObjectIDFastHash64 崩溃还有其他原因(即与您的 MOC 越过线程边界),但据我所知,这种特殊情况(在我的代码中,没有交叉-thread MOC 使用,它在第一次运行时在 iOS 6 上崩溃 [奇怪的是,在我的 CD 后备存储中使用相同的数据集,第二次它没有崩溃] 但在 iOS 7 上没有)在 iOS 中是“修复的” 7. 但是,我无法通过-obtainPermanentIDsForObjects:error 呼叫缓解问题。还在尝试。
  • 我有同样的错误。设置关系时,我只在 iOS 6+ 上获得 EXC_BAD_ACCESS,但在 iOS7 中没有。你找到解决办法了吗?
  • 我通过强制保存到持久存储解决了这个问题。因此,在我的情况下,我在询问了永久 ID 后正在更改子上下文。但是父上下文尚未保存并导致 iOS 6 中的崩溃。在更改或访问子之前尝试保存子和父。检查它的一种方法是确保:objectID.isTemporaryID 为 NO
  • 我希望我能给你+10
【解决方案2】:

我可以看到你正在使用 Magical Record。

在这种情况下,您应该使用他们自己的 MR_save 命令。

无论如何,这不仅仅是 iOS 5 的错误,而是 iOS 5/6,我无法在 7 中重现它。

所以要解决它,因为您提到获得永久 ID 帮助。但不仅如此。

在我的情况下,我在询问了永久 ID 后更改了子上下文。但是父上下文尚未保存并导致 iOS 6 中的崩溃。 在更改或访问孩子之前,我尝试保存孩子和父母,它不再崩溃。 检查它的一种方法是确保:objectID.isTemporaryID 是 NO

【讨论】:

    【解决方案3】:

    有一个类似的错误(也与使用魔法记录有关) - 问题原来是在与创建我的上下文的线程不同的线程上创建临时对象,并尝试访问相同的临时对象引用后的组合-保存。

    所以不要这样做:

    appContext = [NSManagedObject MR_defaultContext]
    temporaryObjects = [thingThatWorksInABackgroundThreadWithContext: appContext]
    [appContext saveToPersistentStoreAndWait]
    NSLog(@"%@", temporaryObjects[0])
    

    改为:

    [MagicalRecord saveWithBlock:^(NSManagedObjectContext * _Nonnull localContext) {
    
        NSArray * tempObjects = [thingThatWorksInSameThreadWithContext:localContext]
    
    }
    completion:^(BOOL success, NSError *error) {
    
        NSArray *savedObjects = [NSArray arrayWithArray:[MyManagedObjectType MR_findAll]];
        NSLog(@"%@", savedObjects[0]);
    
    }
    

    您还需要平台的特定声明以避免应用程序突然终止,请参阅 MR 的文档并在此处保存:https://github.com/magicalpanda/MagicalRecord/blob/master/Docs/Saving-Entities.md

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-23
      • 1970-01-01
      • 1970-01-01
      • 2021-11-14
      相关资源
      最近更新 更多