Получение EXC_BAD_ACCESS при использовании dispatch_async с Core Data - PullRequest
5 голосов
/ 23 февраля 2012

У меня есть изображения в coredata, которые я лениво пытаюсь загрузить для просмотра таблицы. Каждая ячейка использует наблюдателя для связанного основного объекта данных для обновления изображения, когда оно становится доступным. Соответствующий код в сущности выглядит следующим образом:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  // The heavy lifting seems to be during firing of the fault and accessing data,
  // so i'm trying to do that in the background thread.
  UIImage *i = [UIImage imageWithData:self.imageEntity.data];
  // I now need to notify observers that the image is ready on the main thread
  dispatch_async(dispatch_get_main_queue(), ^{
    [self willChangeValueForKey:@"image"];
    image = i;
    [self didChangeValueForKey:@"image"];
  });
});

В проекте используется ARC, я не получаю никаких ошибок или предупреждений компилятора, и когда я запускаю его, это работает, пока я не прокручиваю быстро, а затем я получаю EXC_BAD_ACCESS в строке, когда я объявляю i.

Что мне здесь не хватает?

Ответы [ 3 ]

7 голосов
/ 23 февраля 2012

Видимо, выборка Объекты CoreData не безопасны для потоков .Поэтому предлагается использовать один и тот же persistentStoreCoordinator, но разные ObjectContexts.Вот мой обновленный код, который больше не кажется сбойным:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  @autoreleasepool {
    // Create a new context
    NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc] init];
    // Use an existing coordinator
    NSPersistentStoreCoordinator *coordinator = [[DataSource sharedDataSource] persistentStoreCoordinator];
    [backgroundContext setPersistentStoreCoordinator:coordinator];
    // Getting objectID does not fire the fault, so we grab it but actually fetch the object
    // on a background context to be thread safe.
    Image *imageEntity = (Image*)[backgroundContext objectWithID:self.imageEntity.objectID];
    image = [UIImage imageWithData:imageEntity.data];
    // Notify observers that the image is ready on the main thread
    dispatch_async(dispatch_get_main_queue(), ^{
      [self willChangeValueForKey:@"image"];
      [self didChangeValueForKey:@"image"];
    });
  }
});
1 голос
/ 23 февраля 2012

Dizy, также имейте в виду, что объект Image, созданный в коде:

UIImage *i = [UIImage imageWithData:self.imageEntity.data];

, установлен для автоматического выпуска.Метод dispatch_async выполняется в основной очереди, поэтому существует вероятность того, что выделенная для изображения память может быть освобождена к тому времени, когда основной поток выполнит блок отправки.

0 голосов
/ 23 февраля 2012

CoreData не является потокобезопасным, вам нужно управлять контекстами, чтобы избежать сбоев.Если вы планируете интенсивно использовать множество параллельных процессов для обновления данных в Core Data, я бы посоветовал вам взглянуть на MagicalRecord , удивительный шаблон, вдохновленный Active Record of Rails, который обрабатывает все эти аспектыдействительно умным способом.

...