NSFetchedResultsController Делегированные и фоновые обновления - PullRequest
3 голосов
/ 02 августа 2011

Я столкнулся с проблемой NSFetchedResultsController при разработке приложения для управления гостями.

Приложение в основном загружает список гостей в фоновом режиме (используя подкласс NSOperation), вставляет их в контекст управляемого объекта и затем представляет их в виде таблицы в пользовательском интерфейсе.thread.

Я думаю, что я следую основным правилам многопоточности данных (у меня есть отдельный MOC для операции, созданной в его потоке, я синхронизирую свой основной MOC с помощью уведомления did-save и т. д.).

Что я не до конца понимаю, так это поведение NSFetchedResultsController, который, кажется, вызывает свои методы делегата (controllerDidChangeContent и т. Д.) В фоновом потоке вместо основного потока, что приводит к недопустимым обновлениям пользовательского интерфейса.

Поэтому мой вопрос - законно ли использовать NSFetchedResultsControllerDelegate для наблюдения за изменениями, которые поступают из MOC, при сохранении уведомлений или NSFetchedResultsControllerDelegate предназначен для работы только с изменениями, выполненными в основном потоке?достаточно ясно, если я не могу опубликовать код, чтобы продемонстрировать проблему.

Ответы [ 2 ]

2 голосов
/ 02 августа 2011

Я предполагаю, что ваше уведомление о сохранении MOC отправляется и наблюдается в фоновом потоке вместо основного потока событий.Это приведет к тому, что NSFetchedResultsControllerDelegate будет отправлять сообщения делегатов в фоновом потоке.

Необходимо убедиться, что ваш наблюдатель с уведомлением о сохранении передал управление главному потоку, например:

- (void)backgroundMOCDidSaveNotifiaction:(NSNotification *)notification
{
    [uiMOC performSelectorOnMainThread:
         @selector(mergeChangesFromContextDidSaveNotification:)
     withObject:notification waitUntilDone:NO];
}
0 голосов
/ 25 октября 2015

Отказ

Даниэль Дикисон ответ - это правильный ответ. Я только предлагаю здесь некоторые дополнительные детали и объяснения, так как некоторые из этих шагов не тривиальны.

Использование 2 различных контекстов управляемых объектов - правильное решение

Пользовательский интерфейс MOC:

lazy var mainQueuemanagedObjectContext: NSManagedObjectContext = {
    let coordinator = self.persistentStoreCoordinator
    var managedObjectContext = NSManagedObjectContext(
        concurrencyType: .MainQueueConcurrencyType)
    managedObjectContext.persistentStoreCoordinator = coordinator
    return managedObjectContext
    }()

Транспорт, загрузка, фон MOC:

lazy var transportManagedObjectContext:NSManagedObjectContext = {
    let coordinator = CoreDataStack.sharedInstance.persistentStoreCoordinator
    let managedObjectContext = NSManagedObjectContext(
        concurrencyType: .PrivateQueueConcurrencyType)
    managedObjectContext.persistentStoreCoordinator = coordinator
    return managedObjectContext

    }()

Использование фонового MOC для фоновых операций:

(например, новые данные были загружены и сохранены)

transportManagedObjectContext.performBlockAndWait({ () -> Void in
    // ...add, change, delete objects, then save
    try transportManagedObjectContext.save()
})

Применить Даниэль Дикисон 'ответ на фоновый контекст управляемого объекта в соответствии с документацией Apple :

// Broadcast NSManagedObjectContextDidSaveNotification
NSNotificationCenter.defaultCenter().addObserver(
    self,
    selector: "mocDidSaveNotification:",
    name: NSManagedObjectContextDidSaveNotification,
    object: self.transportManagedObjectContext)

func mocDidSaveNotification(notification:NSNotification)
{
    mainQueuemanagedObjectContext.performSelectorOnMainThread(
        "mergeChangesFromContextDidSaveNotification:",
        withObject: notification,
        waitUntilDone: true)
}

Примечание: Я обычно предпочитаю использовать performBlockAndWait() и waitUntilDone: true, если я не уверен, что не ждет не приведет к условиям гонки. Я приглашаю вас тщательно протестировать вашу заявку, если вы решите не ждать. Я позволю себе заставить фоновый поток ждать пользовательского интерфейса, но никогда наоборот.

Прослушивание из потока пользовательского интерфейса

NSFetchedResultsController must use MainQueueConcurrencyType Context of Managed Object.

let fetchedResultsController = NSFetchedResultsController(
    fetchRequest: fetchRequest,
    managedObjectContext: mainQueuemanagedObjectContext,
    sectionNameKeyPath: "yourKey",
    cacheName: nil)

Ваш NSFetchedResultsController освобождается от фонового контекста управляемого объекта и получает controllerWillChangeContent, didChangeObject и т. Д. после слияние было завершено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...