2013-10-04 6 views
7

Иногда мое приложение падает, когда я хочу обновить файл Core Data, загрузив и проанализировав json-файл. Я получаю следующее сообщение об ошибке:Основные данные: ошибка при удалении/добавлении объектов

CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. -[__NSCFSet addObject:]: attempt to insert nil with userInfo (null)

делает это независимо от того, где я сохранить NSManagedObjectContext в итерации, если изменить свойство во время итерации?

вот мой код:

- (void) updateData 
{   
    dispatch_queue_t serialdQueue; 
    serialdQueue = dispatch_queue_create("update", NULL); 
    dispatch_async(serialdQueue, ^{ 
     [self method1]; 
    }); 
    dispatch_async(serialdQueue, ^{ 
     [self method2]; 
    }); 
    dispatch_async(serialdQueue, ^{ 
     [self method3]; 
    }); 
    dispatch_async(serialdQueue, ^{ 
     [self method4]; 
    }); 
    dispatch_async(serialdQueue, ^{ 
     [self method5]; 
    }); 

} 

-(void)method1 
{   
    //DOWNLOAD JSON FILE 
} 

-(void)method2 //here i add objects to the core data file 
{   
    @try { 

     for (NSDictionary *jsonActivity in [json objectForKey:@"Activities"]) { //ITERATE THROUGH JSON ACTIVITY ARRAY 

      NSFetchRequest *request = [[NSFetchRequest alloc] init]; 

      NSEntityDescription *entity = [NSEntityDescription entityForName:@"Activity" inManagedObjectContext:self.managedObjectContext]; 
      [request setEntity:entity]; 

      NSPredicate *searchFilter = [NSPredicate predicateWithFormat:@"title == %@", [jsonActivity objectForKey:@"title"]]; // CHECK IF OBJECT FROM JSON FILE ALREADY EXISTS... 
      [request setPredicate:searchFilter]; 
      NSError *error = nil; 

      NSArray *results = [self.managedObjectContext executeFetchRequest:request error:&error]; 
      if (error) { 
       NSLog(@"Error %@", error); 
       abort(); 
      } 

      if ([results count] == 0) { // ADD NEW ACTIVITY IF OLD LIST DOESNT CONTAIN IT 

       Activity *activity = [NSEntityDescription insertNewObjectForEntityForName:@"Activity" inManagedObjectContext:self.managedObjectContext]; 

       activity.title = [jsonActivity objectForKey:@"title"]; 

       activity.remove = [NSNumber numberWithBool:NO]; // REMOVE FLAG = NO BECAUSE NEW OBJECTS AREN'T REMOVED 

      } else { 

       Activity *activity = (Activity*) [results objectAtIndex:0]; 
       activity.remove = [NSNumber numberWithBool:NO]; // IF OBJECT ALREADY EXISTS IT SHOULD BE OBTAINED 
      } 

      AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; 
      [appDelegate saveContext]; // SAVE MO CONTEXT 
     } 

    } @catch (NSException *exception) { 

     NSLog(@"Exception: %@", exception); 
    } 
} 

-(void)method3 // DELETE OLD OBJECTS 
{ 
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Activity" inManagedObjectContext:self.managedObjectContext]; 
    [fetchRequest setEntity:entityDescription]; 

    NSPredicate *searchFilter = [NSPredicate predicateWithFormat:@"remove == %@", [NSNumber numberWithBool:YES]]; 
    [fetchRequest setPredicate:searchFilter]; 

    NSArray *objectsToDelete = [[NSArray alloc] init]; 

    NSError *error = nil; 
    objectsToDelete = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; 
    if (error) { 
     NSLog(@"Error %@", error); 
     abort(); 
    } 

    for (Activity *activity in objectsToDelete) { // DELETE OBJECTS WITH THE PROPERTY REMOVE = YES 

     [self.managedObjectContext deleteObject:activity]; // DELETE ACTIVITY 
    } 

    AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; 
    [appDelegate saveContext]; // SAVE MO CONTEXT 
} 

-(void)method4 // CHANGE THE REMOVE PROPERTY TO YES OF ALL OBJECTS 
{   
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Activity" inManagedObjectContext:self.managedObjectContext]; 
    [fetchRequest setEntity:entityDescription]; 

    NSArray *objects = [[NSArray alloc] init]; 

    NSError *error = nil; 
    objects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; 
    if (error) { 
     NSLog(@"Error %@", error); 
     abort(); 
    } 

    for (Activity *activity in objects) { 

     activity.remove = [NSNumber numberWithBool:YES]; 
    } 

    AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; 
    [appDelegate saveContext]; // SAVE MO CONTEXT 

    NSLog(@"End Update"); 
} 

-(void)method5 //UPDATE UI 
{ 
    //UI UPDATES 
} 

ответ

22

Вы не должны получать доступ к управляемому контексту объекта на serialQueue. Взгляните на раздел параллелизма в NSManagedObjectContext documentation.

Если в вашем коде вашего контекст с помощью NSPrivateQueueConcurrencyType или NSMainQueueConcurrencyType типа параллелизма, вы можете использовать один из методов, на основе блока, чтобы убедиться, что вы находитесь на правильную очереди:

//asyncrhonous 
[self.managedObjectContext performBlock:^{ 
    //do stuff with the context 
}]; 

//syncrhonous 
[self.managedObjectContext performBlockAndWait:^{ 
    //do stuff with the context 
}]; 
+0

Вашего ответа фиксированным мою проблему. Я думаю, что мы должны использовать ConcurrencyType очень осторожно, чтобы избежать неожиданной ошибки. – ohyes

Смежные вопросы