Reputation: 5776
Edit: The initial question was wrong, so some of the content might be a bit unrelated. But might give you a better impression of the way I'm doing stuff.
I've got a pretty strange problem with a NSFetchedResultsController
. First I'll describe the current situation of my app. I've got multiple Album
and Photo
entities, which are both subclasses of an abstract class AbstractItem
.
In my AlbumViewController
I'm using to a NSFetchedResultsController
to get all the AbstractItem
's with the current superAlbum
. Like this:
- (NSFetchedResultsController *)fetchedResultsController {
if (!fetchedResultsController ) {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:@"AbstractItem"
inManagedObjectContext:managedObjectContext]];
[request setSortDescriptors:@[
[NSSortDescriptor sortDescriptorWithKey:@"type" ascending:YES],
[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES],
[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]
]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"superAlbum = %@", self.parentAlbum];
[request setPredicate:predicate];
NSFetchedResultsController *newController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:managedObjectContext
sectionNameKeyPath:@"type"
cacheName:nil];
newController.delegate = self;
self.fetchedResultsController = newController;
}
return fetchedResultsController;
}
When I select an Album
, another instance of AlbumViewController
is initiated and pushed on my navigation controller. In that case parentAlbum
is set to the selected object.
Now when I add a new Album
with the following code, the error occurs.
Album *album = (Album *)[Album itemInManagedObjectContext:self.managedObjectContext];
album.name = @"Test album";
album.superAlbum = self.parentAlbum;
NSError *error;
BOOL success = [self.managedObjectContext save:&error];
if (!success) {
NSLog(@"Error: %@", error);
}
The method controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:
gets called for with the type NSFetchedResultsChangeUpdate
for the parentAlbum
object. That one's isn't present in the current NSFetchedResultsController
. So it fails when it tries to update it in the collection view.
How is it possible that an object that isn't in the current NSFetchedResultsController
is used for a notification? And how can I fix this issue?
Edit:
After posting the question, I realized that it actually isn't the NSFetchedResultsController
notifying about the wrong object. But it notifies about an object in the previous (parent) collection view, but it does that to it's own collection view controller.
But that might be just the problem; The collection view controller receives a notification while it isn't visible, looks like it can't handle that at this moment. I handle the notification like this:
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
switch (type) {
case NSFetchedResultsChangeUpdate:
[self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
break;
}
}
I was pretty sure it worked fine before. After iterating over the changes made since last commit, I get it to work again. It did work again after I removed the UICollectionView
header (the supplementary view).
So: My UICollectionView
can't update items when it has an header and it's not currently visible. That was a tough one to discover, but how can this be fixed? Think it's a really strange issue.
The errors I get:
2012-10-04 11:54:21.148 PhotoLibrary[9195:c07] -[NSISObjectiveLinearExpression coefficientForVariable:]: unrecognized selector sent to instance 0x968bae0
2012-10-04 11:54:21.151 PhotoLibrary[9195:c07] CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. -[NSISObjectiveLinearExpression coefficientForVariable:]: unrecognized selector sent to instance 0x968bae0 with userInfo (null)
2012-10-04 11:54:21.156 PhotoLibrary[9195:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSISObjectiveLinearExpression coefficientForVariable:]: unrecognized selector sent to instance 0x968bae0'
*** First throw call stack:
(0x2977012 0x1418e7e 0x2a024bd 0x2966bbc 0x296694e 0xcb06c3 0xcb569c 0xcbf88e 0x58c670 0x5945bd 0x29198fd 0x594605 0x29198fd 0x594605 0x29198fd 0x594605 0x5946c7 0x9cd53 0x5525ff 0x9ea5c 0x5522f7 0x565228 0x56231b 0x55ed4e 0x55edf0 0x8f56 0x1242c1a 0xbcddc9 0x29d10c5 0x292befa 0xb02482 0x11545f3 0x11ede5f 0x114fa26 0x115316e 0x55dc 0x85e5 0x4312c1 0x142c705 0x57920 0x578b8 0x118671 0x118bcf 0x117d38 0x8733f 0x87552 0x653aa 0x56cf8 0x20badf9 0x20baad0 0x28ecbf5 0x28ec962 0x291dbb6 0x291cf44 0x291ce1b 0x20b97e3 0x20b9668 0x5465c 0x26bd 0x25e5)
libc++abi.dylib: terminate called throwing an exception
Upvotes: 3
Views: 3959
Reputation: 539965
I don't know if this is a solution or a workaround, but if you release the fetched results controller in viewWillDisappear
:
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
self.fetchedResultsController = nil;
}
then your ErrorTest program does not crash anymore and seems to work correctly.
This avoids updates to a collection view that is currently not visible.
Since you are already accessing the FRC in viewWillAppear
:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// ...
NSError *error = nil;
BOOL success = [self.fetchedResultsController performFetch:&error];
// ...
}
the FRC will re-created when the view becomes visible again, due to the lazy setter function of the FRC.
Upvotes: 5