In my application I'm using CoreData for storage and displaying data using NSFetchedResultsController.
I followed tutorials from raywenderlich to get it done and it's a lot of code - but it's working properly in general - will post parts of it when it's needed.
I stuck on one problem which I cannot understand.
Data which is displayed inside a UITableView combined with NSFetchedResultsController can be updated in background - and here is where my problem started.
I'm doing Pull-to-refresh approach and starting a download in background on separate thread. It's using it's own NSManagedObjectContext created for this thread and saving it after all objects are created.
Here is code:
- (void)refresh:(id)sender
{
[ServerConnection downloadContactsForToken:token success:^(NSDictionary* responseObject)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSManagedObjectContext* context = [[[AppManager sharedAppManager] createManagedObjectContext] retain];
NSArray* responseContacts = responseObject[@"contacts"];
[responseContacts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
//ContactDB is NSManagedObject
[[[ContactDB alloc] initWithDictionary:obj andContext:context] autorelease];
}];
[context save:nil];
[context release];
dispatch_async(dispatch_get_main_queue(), ^{
[self.refreshControl endRefreshing];
});
});
}];
}
According to what I've read in Apple docs the proper way to detect those changes on main thread NSManagedObjectContext is this:
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(managedObjectContextDidSave:)
name:NSManagedObjectContextDidSaveNotification
object:nil];
}
- (void)managedObjectContextDidSave:(NSNotification *)notification {
dispatch_async(dispatch_get_main_queue(), ^{
if(notification.object != [[AppManager sharedAppManager] managedObjectContext]) {
[[[AppManager sharedAppManager] managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
}
});
}
Basically when I get notification about changes in any managedObjectContext I merge changes to main thread context. And it works in general, but after I started profiling I discovered that all objects that are merged into described process are never deallocated.
When I do everything on main thread - it works - they get deallocated as expected when I scroll UITableView.
I found a workaround and I'm calling:
[[[AppManager sharedAppManager] managedObjectContext] reset];
After merge is done:
[[[AppManager sharedAppManager] managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
[[[AppManager sharedAppManager] managedObjectContext] reset];
But I have no idea why I have to do it and if that's gonna break something else.
Maybe there is a better way to refresh data in background and I'm on completely wrong track.