Dean Davids
Dean Davids

Reputation: 4214

Exception on Core Data save

This seems a fairly common workflow I have an issue with that I cannot figure why. I have a UITableView with NSFetchedResultsController supplying the rows. To add a new object, I insert into context and then present a new view controller to edit the details. The add button action is like so:

    -(IBAction)addNewIssueType:(id)sender
{
    IssueType *newUntitledType = [NSEntityDescription insertNewObjectForEntityForName:@"IssueType" inManagedObjectContext:self.managedObjectContext];
    newUntitledType.name = NSLocalizedString(@"Untitled Task", @"Name for newly created task");
    [self saveContext];

    self.editingType = newUntitledType;
    [self presentNameEditViewForType:newUntitledType];
}

I am crashing with exception at the saveContext method, error:

2013-05-11 16:25:35.990 App [18843:c07] CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. The left hand side for an ALL or ANY operator must be either an NSArray or an NSSet. with userInfo (null)

2013-05-11 16:25:35.992 App [18843:c07] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'The left hand side for an ALL or ANY operator must be either an NSArray or an NSSet.'

* First throw call stack:

Taking the notification observer suggestion as a clue, I looked at my NSFetchedResultsController, presumably the only observer of the NSManagedObjectContext in scope:

-(NSFetchedResultsController *)typesController
{
    if (_typesController) {
        return _typesController;
    }

    // Set up the fetched results controller.
    // Create the fetch request for the entity.
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"IssueType" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];

    // Filter out the required types
    NSPredicate *exclude = [NSPredicate predicateWithFormat:@"NONE name in %@",excludedTypes];
    [fetchRequest setPredicate:exclude];

    // Edit the sort key as appropriate.
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
    NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];

    [fetchRequest setSortDescriptors:sortDescriptors];

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
    aFetchedResultsController.delegate = self;
    self.typesController = aFetchedResultsController;

    NSError *error = nil;
    if (![_typesController performFetch:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        [self failAlertWithMessage:nil forceAbort:YES];
    }

    return _typesController;
}

I found that, if I comment out the lines creating and assigning the predicate, it does not crash. Of course then I am showing some objects that I want hidden. I can't see anything wrong with the predicate itself, fetch does return the expected objects and excludes those in the excludedTypes Array as intended.

Save context method does not have any issues on editing or deleting existing objects, only on inserting a new object.

I am not using and threads here other than the main thread.

Upvotes: 3

Views: 939

Answers (1)

Martin R
Martin R

Reputation: 539945

NONE is an alias for NOT ANY and is indeed for to-many relationships. What you probably want is:

[NSPredicate predicateWithFormat:@"NOT name in %@", excludedTypes];

Upvotes: 4

Related Questions