iOS 5 Core Data freeze

前端 未结 7 916
清歌不尽
清歌不尽 2021-01-30 22:48

I try to do the following simple thing:

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

Nothing fancy.

7条回答
  •  北荒
    北荒 (楼主)
    2021-01-30 23:15

    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.

提交回复
热议问题