从后台恢复后访问核心数据NSManagedObject会使应用程序崩溃

我正在使用核心数据,并发现应用程序有时会在从后台恢复后崩溃。 当我尝试访问NSManagedObject子类上的属性时,我已经确定了块方法体内发生的崩溃。

我有一个属性,它包含对NSManagedObject子类的引用。

@property(非primefaces,强)CalItem * calObject;

为了重现崩溃,我首先需要调用子viewController( NoteViewController )传递一个块( NoteTextBlock )。

 NoteViewController *noteViewController = [[NoteViewController alloc]initWithNote:self.calObject.note NoteTextBlock:^(NSString *noteText) { self.calObject.note = noteText; //crashing here }]; 

然后将应用程序发送到后台并恢复它。 然后在NoteViewController中,我将向调用viewController返回一条消息。

 if (self.noteTextBlock) { self.noteTextBlock(trimmedString); } 

当块返回并执行self.calObject.note = noteText ,应用程序崩溃。

显然你不能把一个块放在堆栈上,然后恢复应用程序,然后继续使用块内定义的内容? 或者我在这里做错了什么?

编辑:
*** Terminating app due to uncaught exception 'NSObjectInaccessibleException', reason: 'CoreData could not fulfill a fault for '0xb253100 ''

这个块在子viewController中定义如下:

 @property(nonatomic, copy)NoteTextBlock noteTextBlock; 

EDIT2
这是我在崩溃的行上设置断点时得到的结果。
(lldb) po self.calObject
$2 = 0x0b4464d0 (entity: DTODay; id: 0xb489d00 ; data: )

我正在使用MagicalRecord lib来管理所有Core Data的东西。

 - (void)applicationDidBecomeActive:(UIApplication *)application { if ([NSManagedObjectContext MR_defaultContext] == nil || [NSManagedObjectModel MR_defaultManagedObjectModel] == nil || [NSPersistentStoreCoordinator MR_defaultStoreCoordinator] == nil || [NSPersistentStore MR_defaultPersistentStore] == nil ) { //coming back from background, re-init coredata stack [MagicalRecordHelpers setupCoreDataStackWithAutoMigratingSqliteStoreNamed:DBNAME]; } 

我不熟悉MagicalRecords,但……

当您在商店中不再存在(或从未存在)的非故障 (在Edit2中可以看到)对象时,会引发此exception。
在少数情况下可能会发生这种情况:

  1. 另一个上下文已将其从商店中删除
  2. 您已插入它,获得了永久ID,并且:
    **刷新它
    **保存它(但只保存到父上下文),重置父节点,并刷新当前上下文中的对象(或将其作为故障导入主上下文),请参阅objectWithID:

可能还有其他一些我忘记或不知道的情况。

如果你能描述你的堆栈结构,你的对象状态/来源我们可能能够更好地理解这个问题

尝试在backgound上保存状态,然后在AppDelegate.m中唤醒时恢复状态

  - (void)applicationDidEnterBackground:(UIApplication *)application { /* Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. */ [MagicalRecord cleanUp]; } - (void) applicationDidBecomeActive:(UIApplication *)application { /* Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. */ [MagicalRecord setupCoreDataStackWithStoreNamed:DBNAME]; } 

我从未使用过Magical Record,但在我看来,当应用程序再次变为活动状态时,您正在重建现有的Core Data堆栈。 我想你真正想做的是在applicationDidFinishLaunching:(UIApplication *)设置核心数据applicationDidFinishLaunching:(UIApplication *)而不是applicationDidBecomeActive:(UIApplication *)

前者仅在应用程序启动时设置堆栈,而后者将在每次应用程序“唤醒”时重新设置堆栈。

问题是您已经创建了一个新的Core Data堆栈,同时拥有引用旧Core Data堆栈的对象。

通常,当应用程序启动时,您需要创建堆栈。 当应用程序终止时,您可以尝试干净地删除堆栈。 但是,当它刚刚进入后台时,您应该只保存数据,然后当简单地重新激活应用程序时,您真的不需要做任何事情。