Accessing a core data NSManagedObject after resuming from background crashes the app

回眸只為那壹抹淺笑 提交于 2019-12-22 05:24:20

问题


I'm using core data and have found the app sometimes crashing after resuming from background. I've identified the crash occurring inside a block method body when I try to access a property on a NSManagedObject subclass.

I have a property which holds a reference to a NSManagedObject subclass.

@property(nonatomic,strong) CalItem *calObject;

To reproduce the crash I first need to call the child viewController(NoteViewController) passing a block (NoteTextBlock).

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

Then send the app to background and resume it. Afterwards in the NoteViewController I'll return a message to the calling viewController.

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

When the block returns and the line self.calObject.note = noteText gets executed the app crashes.

So apparently you can't put a block on the stack, quite and resume the app and then continue with what was defined inside the block ? Or am I just doing something wrong here ?

Edit:
*** 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>''

The block is defined like this inside the child viewController:

@property(nonatomic, copy)NoteTextBlock noteTextBlock;

Edit2
This is what I get when I set a breakpoint on the line where it crashes.
(lldb) po self.calObject
$2 = 0x0b4464d0 <DTODay: 0xb4464d0> (entity: DTODay; id: 0xb489d00 <x-coredata://C2304B7C-7D51-4453-9993-D33B9113A7A5/DTODay/p57> ; data: <fault>)

I'm using the MagicalRecord lib to manage all the Core Data stuff.

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

回答1:


I am not familiar with MagicalRecords, but ...

This exception is raised when you have an un-faulted (as can be seen in Edit2) object that no longer (or never had) exists in the store.
This might happen in a few cases:

  1. Another context has deleted it from the store
  2. You have inserted it, obtained a permanent id for it and:
    ** refreshed it
    ** saved it (but only to the parent context), reseted the parent, and refreshed the object in the current context (or imported it as fault to your main context), see objectWithID:

There might be other cases i'm forgetting, or unaware of.

if you could describe your stack structure, and your object state/origin we might be able to understand the problem better




回答2:


Try also saving state on backgound and then restoring state on wake up in your 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]; 
}



回答3:


I have never used Magical Record, but it looks to me that you are rebuilding an existing Core Data stack when the application becomes active again. I imagine what you really want to do is setup the Core Data in applicationDidFinishLaunching:(UIApplication *) instead of applicationDidBecomeActive:(UIApplication *).

The former will only setup the stack when the app launches, while the latter will re-setup the stack every time the app "wakes up."

The problem is that you then have created a new Core Data stack, while having objects that reference the old Core Data stack.

In general, when the app starts, you want to create your stack. You can try to cleanly take down the stack when the app terminates. However, when it just goes to the background, you should simply save the data, and then you really don't have to do anything when the app is simply re-activated.



来源:https://stackoverflow.com/questions/15833305/accessing-a-core-data-nsmanagedobject-after-resuming-from-background-crashes-the

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!