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

时间:2013-04-05 11:54:24

标签: ios objective-c core-data objective-c-blocks

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

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

  

@property(非原子,强)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 <x-coredata://C2304B7C-7D51-4453-9993-D33B9113A7A5/DTODay/p57>''

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

@property(nonatomic, copy)NoteTextBlock noteTextBlock;

EDIT2
这是我在崩溃线上设置断点时得到的结果 (lldb) po self.calObject
$2 = 0x0b4464d0 <DTODay: 0xb4464d0> (entity: DTODay; id: 0xb489d00 <x-coredata://C2304B7C-7D51-4453-9993-D33B9113A7A5/DTODay/p57> ; data: <fault>)

我正在使用MagicalRecord lib管理所有核心数据。

- (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];
    }

3 个答案:

答案 0 :(得分:2)

尝试在后台保存状态,然后在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]; 
}

答案 1 :(得分:2)

我不熟悉MagicalRecords,但是......

如果商店中不再存在(或从未存在)无故障(在Edit2中可见)对象,则会引发此异常。
在少数情况下可能会发生这种情况:

  1. 另一个背景已将其从商店中删除
  2. 您已插入,获得了永久ID,并且:
    **刷新它 **保存它(但仅限于父上下文),重置父项,并刷新当前上下文中的对象(或将其作为错误导入主上下文),请参阅objectWithID:
  3. 可能还有其他一些我忘记或不知道的情况。

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

答案 2 :(得分:0)

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

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

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

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