问题
Ok I get more and more general with this question, since I've noticed several lags in my app due to this. I've noticed the problem with reordering, but it happens in other places as well. I have a CoreDataViewController class which all my table view controllers subclass. And in this class I basically have all NSFetchedResultsController delegate methods as they are in the apple docs.
Then I've tried to find out how often changes are noticed by this NSFetchedResultsController to find out where my time lag is:
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
if(self.suspendAutomaticTrackingOfChangesInManagedObjectContext) return;
NSLog(@"ControllerDidChangeContent");
TICK;
[self.tableView endUpdates];
TOCK;
}
So for example in my view controller A, I have this fetch request (called from viewDidLoad):
- (void)setupFetchedResultsController
{
//NSError *error = nil;
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SpendingCategory"];
request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"position" ascending:YES]];
//[self.mainCategory.managedObjectContext executeFetchRequest:request error:&error];
request.predicate = [NSPredicate predicateWithFormat:@"belongsToMainCategory = %@", self.mainCategory];
self.fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:request
managedObjectContext:self.mainCategory.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
}
If I change attributes for my objects in this view controller, my log prints out only once the comment "ControllerDidChangeContent" as it should. And is as fast as expected. And I mean really only a simple attribute change, just changing some number or string etc. such as:
spendingCategory.name = @"Hello world";
If however I've already accessed another view controller which setups its NSFetchedResultsController as well in viewDidLoad, my log is printed out twice. Here is the second NSFetchedResultsController:
- (void)setupFetchedResultsController
{
self.managedObjectContext = ((AppDelegate *)[[UIApplication sharedApplication] delegate]).managedObjectContext;
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SpendingCategory"];
NSSortDescriptor *mainCatPosition = [[NSSortDescriptor alloc]
initWithKey:@"belongsToMainCategory.position" ascending:YES];
NSSortDescriptor *spendingCatPosition = [[NSSortDescriptor alloc]
initWithKey:@"position" ascending:YES];
request.sortDescriptors = [NSArray arrayWithObjects:mainCatPosition,spendingCatPosition,nil];
request.predicate = [NSPredicate predicateWithFormat:@"liveBudget = %@", [NSNumber numberWithBool:YES]];
self.fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:request
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:@"belongsToMainCategory.position"
cacheName:@"LiveBudget"];
}
My before mentioned simple attribute change takes way longer. And that's because now my log prints out twice (!) ControllerDidChangeContent. The first TICK-TOCK is still as fast as before, but the second takes over one second. And I guess this is because I have two NSFetchedResultsController watching the same entity.
Question: I still don't quite understand why they influence each other? I mean ok I update an attribute in one view controller so the other one should of course notice this change, but why are two didChangeContent triggered?
Question: How can I avoid that? Or how can I improve that?
回答1:
I assume it is better to check why the 1[sec] halt before turning to this solution.
myself, I have not experienced that delay when using multiple FRC's on the same context so my guess is the problem lie elsewhere.
as for your questions:
The FRC is listening for 'NSManagedObjectContextObjectsDidChangeNotification' so all FRC's listening on the same context on the same objects will trigger their delegate's methods when these objects are changed. Hence, it is clear why your log is printed twice (2 different FRC's changed their content)
1[sec] is a long time for blocking the main thread and should be addressed (check with instruments what can be done). As I mentioned, there is no way to avoid that when using FRC's on the same context, but you can create a child context for each VC you stem an make the FRC listen to that child context only, then changes will only be visible to other FRC when you save down the context chain. as long as your VC stack is not very deep this should not be a real problem. In any case you want your other VC's to get updated with changes as they update the tableview to give a smooth user experience, so if the update take too long you should see why.
来源:https://stackoverflow.com/questions/20940047/nsfetchedresultscontrollers-in-different-view-controllers-updating-each-other