Sometimes my app crashes when I want to update my Core Data file by downloading and parsing a json file. I get the following error:
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)
Does it matter where I save the NSManagedObjectContext within an iteration if I change properties during iteration?
here is my code:
- (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
}
Table views have a built-in swipe to delete mechanic that we can draw upon to let users delete commits in our app. Helpfully, managed object context has a matching delete() method that will delete any object regardless of its type or location in the object graph.
A delete rule defines what happens when the record that owns the relationship is deleted. Select the notes relationship of the Category entity and open the Data Model Inspector on the right. By default, the delete rule of a relationship is set to nullify. Core Data supports four delete rules: No Action.
In Core Data, faults are placeholders, or “unrealized objects”. They are small objects which refer to other NSManagedObjects, which are fetched into memory only as needed. This faulting mechanism is designed to enhance performance and reduce memory use.
An object space to manipulate and track changes to managed objects.
You shouldn't be accessing your managed object context on serialQueue
. Take a look at the Concurrency section of the NSManagedObjectContext
documentation.
If in your code your context is using NSPrivateQueueConcurrencyType
or NSMainQueueConcurrencyType
concurrency type, you can use one of the block-based methods to ensure you're on the right queue:
//asyncrhonous
[self.managedObjectContext performBlock:^{
//do stuff with the context
}];
//syncrhonous
[self.managedObjectContext performBlockAndWait:^{
//do stuff with the context
}];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With