vendredi 31 juillet 2015

Core Data update locations for positions in background cause blocking UI

I am using 3 Managed Object Contexts Architecture (creating temporaryContext for background which parent is managedObjectContext - UI, and which has parent writerObjectContext which should write to database in background) and I have a problem with blocking UI when I updating objects. Example would be best. So I have thousands of points in my database and I am using NSFetchedResultsController with tableView for getting them. Here is my code:

- (void)viewDidLoad
{
    [super viewDidLoad];

    temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    temporaryContext.parentContext = [[CoreDataManager manager] managedObjectContext];
    temporaryContext.undoManager = nil;

    ...
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{   
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:PositionCellIdentifier forIndexPath:indexPath];
    [self configureCell:(PanelPositionCell *)cell atIndexPath:indexPath];
    return cell;
}

- (void)configureCell:(PanelPositionCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    // Fetch Record
    NSManagedObject *record = [self.fetchedResultsController objectAtIndexPath:indexPath];
    OpenPositionCD *position = (OpenPositionCD *)record;

    // Update Cell
    [cell setValuesByOpenPositionCD:position];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        [self checkAddress:position];
    });
}

- (void)checkAddress:(OpenPositionCD *)openPosition {
    if (openPosition.latitude == 0 && openPosition.longitude == 0) {
        return;
    }

    if ([openPosition hasAddress]) {
        return;
    }

    CLLocation *location = [[CLLocation alloc]initWithLatitude:[openPosition.latitude doubleValue] longitude:[openPosition.longitude doubleValue]];
    [[LocationManager manager] getPlacemarksForLocation:location withCompletion:^(NSArray *placemarks, NSError *error) {
        if (!error) {
                openPosition.address = placemarks[0];
                            NSError *error = nil;
                if (![temporaryContext save:&error]) {
                    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                }
        }
    }];
}

When I am scrolling to cells which don't have addresses the UI is freeze often which depends on how fast I am scrolling. So how can I fix it? I was trying with/without dispatch_async and with/without temporaryContext performBlock but looks nothing can help me. So thanks for any help.

I am adding initializing of contexts in CoreDataManager but I hope it's allright:

// Returns the managed object context for the application.
// If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
- (NSManagedObjectContext *)managedObjectContext{
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }

    _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    _managedObjectContext.parentContext = [self writerManagedObjectContext];

    return _managedObjectContext;
}

// Writer context for database
- (NSManagedObjectContext *)writerManagedObjectContext{
    if (_writerManagedObjectContext != nil) {
        return _writerManagedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        _writerManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        [_writerManagedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return _writerManagedObjectContext;
}

Aucun commentaire:

Enregistrer un commentaire