Основные положения обновления данных для позиций в фоновом режиме вызывают блокировку пользовательского интерфейса
Я использую архитектуру 3 контекстов управляемых объектов (создаю временный контекст для фона, родитель которого - управляемый интерфейс объекта - UI, а родительский объект - writerObjectContext, который должен выполнять запись в базу данных в фоновом режиме), и у меня возникает проблема с блокировкой пользовательского интерфейса при обновлении объектов. Пример будет лучшим. Итак, у меня есть тысячи точек в моей базе данных, и я использую NSFetchedResultsController
с tableView
для получения их. Вот мой код:
- (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]);
}
}
}];
}
Когда я прокручиваю до ячеек, у которых нет адресов, пользовательский интерфейс часто зависает, что зависит от того, насколько быстро я прокручиваю. Так как я могу это исправить? Я пытался с / без dispatch_async
и с / без temporaryContext performBlock
но выглядит ничто не может помочь мне. Так что спасибо за любую помощь.
Я добавляю инициализацию контекстов в CoreDataManager, но надеюсь, что все в порядке:
// 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;
}
1 ответ
Вы используете устаревшие API. Рекомендуемый способ использования нескольких контекстов - не назначать один и тот же постоянный координатор хранилища дочернему контексту, а вместо этого назначать ему parentContext
,
Вы, вероятно, хотите настройки М. Зарры с
WriterContext (background)
MainContext (main thread, parent is WriterContext)
WorkerContext (background, parent is MainContext, create and destroy as needed)
Вы бы сделали фоновую работу в рабочем контексте и save
что подтолкнет изменения в основной контекст. Вы можете сохранить основной контекст, когда это удобно, а хранилище данных попадает в фоновый режим только при сохранении контекста записи.
Наконец, вы используете объект позиции в другом потоке. Вы должны обернуть ваши звонки в рабочий контекст performBlock
блок для безопасного использования этих объектов.