views:

38

answers:

3

I'm trying to implement the Paparazzi 2 assignment from the Stanford CS193 course and I'm running into a problem. My one call to save the database is when the app exits (I'm borrowing heavily from Mike Postel's version to check my code):

- (void)applicationWillTerminate:(UIApplication *)application {
    if (flickrContext != nil) {
        if ([flickrContext hasChanges] == YES) {
            NSError *error = nil;
            BOOL isSaved = [flickrContext save:&error];
            NSLog(@"isSaved? %@", (isSaved ? @"YES" :@"NO") );

            // Replace this implementation with code to handle the error appropriately.
            if(isSaved == NO){
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }
        } 
    }
}

Unfortunately, this doesn't seem to be doing the job. I'm getting the occasional EXEC_BAD_ACCESS call that might be related to this, but the database never saves. I've inserted the save into other pieces and it works fine there, just not in this routine. I'm not releasing any of the managed objects in my views, just the managed object context (flickrContext, or whatever I'm calling it in a view).

Any ideas?

A: 

flickrContext is your managedObjectContext? I'm betting it is nil or otherwise hosed when you hit this method. You say you are releasing it in a view - surely you should be creating just one, having it owned by the application delegate, and release it only in app delegate's dealloc?

(And when you need to use it -

NSManagedObjectContext* moc = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];

)

Regarding your EXEC_BAD_ACCESS - what happens with NSZombieEnabled = YES? What does the static analyzer say?

Adam Eberbach
His line "I'm not releasing any of the managed objects in my views, just the managed object context (flickrContext, or whatever I'm calling it in a view)." sounds odd, too. Did he say he released the moc? That's surely bad.
Yuji
+2  A: 

Are you sure that applicationWillTerminate: is even being called?

With iOS4 and background process support, the usual application lifecycle is now:

running -> background -> background suspended -> exit

You get an applicationDidEnterBackground: call when transitioning into the background state, but no further notification when the background process suspends or exits.

So, you really need to save state in applicationDidEnterBackground: for iOS4, as well as in applicationWillTerminate: for older versions

David Gelhar
If the user double-taps to open the task manager and kills an app it will still get applicationWillTerminate, right? Just making sure this iOS 4 change won't result in lost data in the case you describe.
Adam Eberbach
@Adam No, I believe you do NOT get applicationWillTerminate when the app is killed from the task manager (just confirmed that by testing in the simulator). applicationDidEnterBackground is really your only opportunity to save data, because you may not get to run again before being quit.
David Gelhar
A: 

Good call. I actually solved this one the old fashioned (brute force) way. It turns out that applicationWillTerminate wasn't being called, but it wasn't obvious. The routine to create the database that I had borrowed from the web was explicitly releasing an NSArray that I'm pretty sure was autoreleased. It essentially turned the program into a time bomb. Although I still haven't figured out why it lasted as long as it did and just didn't manifest until I tried to exit.

I'm still learning XCode and CocoaTouch. I know about NSZombieEnabled but I haven't figured out how to use it correctly yet. I'm still in the ham-fisted monkey stage. Thanks for the tips, though. They were helpful.

indigosplinter