Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS 5 Core Data freeze

I try to do the following simple thing:

NSArray * entities = [context executeFetchRequest:inFetchRequest error:&fetchError]; 

Nothing fancy. But this freezes in iOS 5, it works fine in iOS 4. I don't get exceptions, warnings or errors; my app just simply freezes.

Please help me out! I'm dying here! ;)

like image 215
Dries De Smet Avatar asked Oct 18 '11 13:10

Dries De Smet


1 Answers

I don't know if you also use different Thread. If yes the issue comes from the fact that NSManagedObjects themselves are not thread-safe. Creating a ManagedContext on the main thread and using it on another thread freezes the thread.

Maybe this article can help you : http://www.cimgf.com/2011/05/04/core-data-and-threads-without-the-headache/

Apple has a demo application for handling Coredata on several threads (usually main & background threads) : http://developer.apple.com/library/ios/#samplecode/TopSongs/Introduction/Intro.html

What I've done to solve this issue is :

  • In the application delegate : create the persistent store (one for all thread) and create the Coredata managed Context for the main thread,
  • In the background thread, create a new managed context (from same persistent store)
  • Notifications are used when saving, to let the mainContext know when background thread has finished (inserting rows or other).

There are several solutions, using a NSQueueOperation. For my case, I'm working with a while loop. Here is my code if it may help you. However, Apple documentation on concurrency and their Top Songs example application are good points to start.

in the application delegate :

 -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {     // Override point for customization after application launch.      self.cdw = [[CoreDataWrapper alloc] initWithPersistentStoreCoordinator:[self persistentStoreCoordinator] andDelegate:self];     remoteSync = [RemoteSync sharedInstance];      ...      [self.window addSubview:navCtrl.view];     [viewController release];      [self.window makeKeyAndVisible];     return YES;  }      - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {     if (persistentStoreCoordinator == nil) {         NSURL *storeUrl = [NSURL fileURLWithPath:self.persistentStorePath];         NSLog(@"Core Data store path = \"%@\"", [storeUrl path]);         persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:nil]];         NSError *error = nil;         NSPersistentStore *persistentStore = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error];         NSAssert3(persistentStore != nil, @"Unhandled error adding persistent store in %s at line %d: %@", __FUNCTION__, __LINE__, [error localizedDescription]);     }     return persistentStoreCoordinator; }   -(NSManagedObjectContext *)managedObjectContext {     if (managedObjectContext == nil) {         managedObjectContext = [[NSManagedObjectContext alloc] init];         [managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];     }     return managedObjectContext; }  -(NSPersistentStoreCoordinator *)persistentStoreCoordinator {     if (persistentStoreCoordinator == nil) {         NSURL *storeUrl = [NSURL fileURLWithPath:self.persistentStorePath];         NSLog(@"Core Data store path = \"%@\"", [storeUrl path]);         persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:nil]];         NSError *error = nil;         NSPersistentStore *persistentStore = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error];         NSAssert3(persistentStore != nil, @"Unhandled error adding persistent store in %s at line %d: %@", __FUNCTION__, __LINE__, [error localizedDescription]);     }     return persistentStoreCoordinator; }   -(NSManagedObjectContext *)managedObjectContext {     if (managedObjectContext == nil) {         managedObjectContext = [[NSManagedObjectContext alloc] init];         [managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];     }     return managedObjectContext; }   -(NSString *)persistentStorePath {     if (persistentStorePath == nil) {         NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);         NSString *documentsDirectory = [paths lastObject];         persistentStorePath = [[documentsDirectory stringByAppendingPathComponent:@"mgobase.sqlite"] retain];     }     return persistentStorePath; }  -(void)importerDidSave:(NSNotification *)saveNotification {     if ([NSThread isMainThread]) {         [self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];     } else {         [self performSelectorOnMainThread:@selector(importerDidSave:) withObject:saveNotification waitUntilDone:NO];     } } 

In the object running the background thread :

monitor = [[NSThread  alloc] initWithTarget:self selector:@selector(keepMonitoring) object:nil];  -(void)keepMonitoring{     while(![[NSThread currentThread]  isCancelled]) {         NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];             AppDelegate * appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];          //creating the cdw here will create also a new managedContext on this particular thread         cdwBackground = [[CoreDataWrapper alloc] initWithPersistentStoreCoordinator:appDelegate.persistentStoreCoordinator andDelegate:appDelegate];         ...     } } 

Hope this help,

M.

like image 118
Michael A. Avatar answered Oct 23 '22 20:10

Michael A.