开发者

NSFetchedResultsController based Table View always fails on SECOND insert of entity

I am using an NSFetchedResultsController to manage displaying fetched managed objects in a table view that has one section. The table starts out empty and the user can add new entities to it using the UI. As it stands, the program always works when adding the first entity, and always crashes when adding a second. There is sometimes no error presented upon the crash and other times there are errors of differing types (some included below). Through log statements and tracing I see that the program crashes just after the NSFetchResultsController's delegate's controllerWillChangeContent (which calls [self.tableView beginUpdates];) method exits, but before any other method in my code is called. Here are some of the relavant parts of my code. Configuring the NSFetchedResultsController:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Beer"
                                    inManagedObjectContext:self.managedObjectContext]];

// Configure request's entity and predicate
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];

NSString *expression = [NSString stringWithFormat:@"brewery.name LIKE \"%@\"开发者_JAVA百科", self.brewery.name];
NSPredicate *predicate = [NSPredicate predicateWithFormat:expression];
[fetchRequest setPredicate:predicate];
self.resultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                                             managedObjectContext:self.managedObjectContext
                                                               sectionNameKeyPath:nil
                                                                        cacheName:nil];
self.resultsController.delegate = self;
[fetchRequest release];

NSError *error = nil;
BOOL success = [resultsController performFetch:&error];
if (!success) {
    NSLog(@"Error fetching request %@", [error localizedDescription]);
}

Adding new entity:

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Beer" inManagedObjectContext:self.managedObjectContext];
Beer *beer = [[Beer alloc] initWithEntity:entity insertIntoManagedObjectContext:self.managedObjectContext];
beer.name = beerName;
beer.brewery = self.brewery;

I have seen the warnings in the docs about problems displaying tables with one section, and I have used Apple's workaround for that to no avail. Those methods aren't getting called prior to the crash anyway.

Some of the errors I've received:

Serious application error.  Exception was caught during Core Data change processing: *** -[NSCFString compareObject:toObject:]: unrecognized selector sent to instance 0x4e808c0 with userInfo (null)
Serious application error.  Exception was caught during Core Data change processing: *** -[CALayer compareObject:toObject:]: unrecognized selector sent to instance 0x4e53b80 with userInfo (null)
Serious application error.  Exception was caught during Core Data change processing: *** -[UITextTapRecognizer controllerWillChangeContent:]: unrecognized selector sent to instance 0x4ca5d70 with userInfo (null)
Serious application error.  Exception was caught during Core Data change processing: *** -[CALayer controllerWillChangeContent:]: unrecognized selector sent to instance 0x4e271a0 with userInfo (null)
Serious application error.  Exception was caught during Core Data change processing: *** -[NSCFNumber countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x4c96ee0 with userInfo (null)

As you can see, the errors (when one was presented) are not consistent, even when no change to the code was made.

Can anyone figure out what I'm doing wrong?


Your inconsistent errors point to a possible over-release issue. Especially since changing your delegates to just reload the data makes the issue go away. Personally I would invest the time to solve the issue rather than coding around it as you definitely having a code issue there that will probably show up later somewhere else.

I would do the following:

  1. Turn on NSZombie
  2. Add a breakpoint for objc_exception_throw
  3. Run in the debugger

When the exception occurs, look at the memory address and see what is being accessed and where. This will isolate the issue and tell you what is going on. It would also be helpful, if that does not reveal the issue, to post your NSFetchedResultsController delegate methods so I can see if there is anything strange in them.

Best to update the original question with the additional information.


Your code to create new entities is all weird. What about using this instead:

Beer* beer = [NSEntityDescription insertNewObjectForEntityForName: @"Beer" 
    inManagedObjectContext: self.managedObjectContext];
beer.name = @"Grolsch";

Also, you are not calling NSManagedObjectContext#save:. But maybe you are doing that in a part of your code that you did now show?


While I did not solve this particular problem, I took a slightly different approach to writing the class that gave the the functionality I want and did not cause the problem to arise. I am still using NSFetchedResultsController, but rather than implementing all four delegate methods, I am only implementing controllerDidChangeContent:, which just calls [tableView reloadData].

This is the implementation that is included in the RootViewController class if you create a new Navigation-Based Application in XCode that uses Core Data for storage. You probably lose some control over table-edit animations, but it's much simpler and works fine for my purposes.


I had a similar bug recently - your problem is with over releasing, particularly:

[sortDescriptors release];

You get the sortDescriptors object from

[NSArray arrayWithObjects:sortDescriptor, nil];

which doesn't have "alloc", "copy" or "new", so it returns an autoreleased object. Because you release it early, you get two places where you can crash - when the NSFetchRequest uses it, and when it is released by the pool. See apple's memory management guide for more details.


This is an old one but for the benefit of others having the same problem, I've spent hours trying to understand what was going on and have finally found an issue with my sort descriptor that was causing these random crashes.

The error messages varied but were mostly related to a compareObject:toObject selector as per below.

-[_NSCFSet compareObject:toObject:]: unrecognized selector sent to instance -[_NSCFString compareObject:toObject:] unrecognized selector sent to instance

My suggestion is to try and eliminate all sort descriptors and predicates from your code and then add them one by one to find where the problem is.

Good luck! Rog

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜