在执行[self.managedObjectContext save:& error]时,在NSOperation上的某个时候SEGV_ACCERR和崩溃应用程序

时间:2013-01-13 01:14:56

标签: iphone core-data nsmanagedobjectcontext nsoperation

我有一个问题,我无法理解如何处理因为逻辑上没有发生。

我有一些同时运行的NSOperation个。例如,

- (void)main
{
    @autoreleasepool
    {        
        AppDelegate *appController = (AppDelegate *)[[UIApplication sharedApplication] delegate];

        self.managedObjectContext = [[NSManagedObjectContext alloc] init];
        [self.managedObjectContext setUndoManager:nil];
        [self.managedObjectContext setPersistentStoreCoordinator: [appController persistentStoreCoordinator]];

        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 
        [nc addObserver:self
               selector:@selector(mergeChanges:) 
                   name:NSManagedObjectContextDidSaveNotification
                 object:self.managedObjectContext];
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        NSEntityDescription *entity = [NSEntityDescription 
                                       entityForName:@"Entity" inManagedObjectContext:self.managedObjectContext];
        [fetchRequest setEntity:entity];

        [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"%K != %@",@"number1",[NSNumber numberWithInt:2]]];

        NSError *error;
        NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];

        for (NSManagedObject *obj in fetchedObjects) {

            //Do Something with managed object then save        
            NSError *error = nil;
            //[episode release];
            if (![self.managedObjectContext save:&error]) {
                // Replace this implementation with code to handle the error appropriately.
                // abort() causes the application to generate a crash log and terminate.
                // You should not use this function in a shipping application, although it may be useful
                // during development. If it is not possible to recover from the error, display an alert
                // panel that instructs the user to quit the application by pressing the Home button.
                //
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }
        }
    }
}

- (void)mergeChanges:(NSNotification *)notification
{
    AppDelegate *appController = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *mainContext = [appController managedObjectContext];

    // Merge changes into the main context on the main thread
    [mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) 
                              withObject:notification
                           waitUntilDone:YES];  
} 

这是我的典型NSOperation,它同时工作并在核心数据中更新我的对象,有时没有解释应用程序崩溃,我在这一行收到错误:

if (![self.managedObjectContext save:&error])

在我的崩溃报告中,我的问题是,有一种方法可以防止应用程序崩溃并修复错误吗?我执行@syncronized时可以使用save吗?这是由于不同的线程和不同的对象?我该如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

移动您用于合并app delegate中的更改的代码。

因此,在application:didFinishLaunchingWithOptions:注册通知。

NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 
[nc addObserver:self
       selector:@selector(mergeChanges:) 
           name:NSManagedObjectContextDidSaveNotification
         object:nil]; // set nil here

然后,始终在应用委托中创建您的mergesChanges:方法。在这里,您需要确保通知在主线程上运行,并且您收到通知的上下文与主要线程不同。

- (void)mergeChanges:(NSNotification *)notification
{
    if ([notification object] == [self managedObjectContext])
        return;

    if (![NSThread isMainThread]) {
        [self performSelectorOnMainThread:@selector(mergeChanges:) withObject:notification waitUntilDone:YES];
        return;
    }

    NSManagedObjectContext *mainContext = [self managedObjectContext];

    // Merge changes into the main context on the main thread
    [mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) 
                              withObject:notification
                           waitUntilDone:YES];  
}

P.S。在这里,您使用的是非并发NSOperation,如果插入NSOperationQueue,将以并发方式运行(队列,通过GCD将为您管理)。

答案 1 :(得分:1)

这不是并发操作。并且您的mergeChanges通知可能永远不会被调用,因为一旦main方法完成,操作将被解除分配(可能在NSManagedObjectContextDidSaveNotification选择器执行之前)。

如果您希望并行操作在完成之前一直存在,则需要覆盖start方法和isConcurrent方法。您可能会收到此错误,因为您的NSError或选择器在完成之前超出了范围。我建议阅读本文以了解并发与非并发操作的工作原理:

请查看Dave Dribin的Concurrent Operations Demystified了解更多详情。