Удаление в фоновом режиме не работает после запуска - PullRequest
1 голос
/ 29 января 2012

Я пытаюсь создать некоторые методы, которые облегчат выполнение базовых данных в фоновом режиме.То, что я делаю:

  • Используйте NSOperationQueue -addOperationWithBlock: для создания фонового потока
  • В фоновом потоке создайте NSManagedObjectContext с тем же persistentStoreCoordinator в качестве контекста в главном потоке и с undoManager, установленным на nil
  • Добавить наблюдателя в центр уведомлений по умолчанию для прослушивания NSManagedObjectContextDidSaveNotification уведомлений и обрабатывать их так:

    - (void)mergeChanges:(NSNotification *)notification
    {
        dispatch_sync(dispatch_get_main_queue(), ^{
            [_mainContext mergeChangesFromContextDidSaveNotification:notification];
        });
    }
    
  • Выполнить блок, который был передан и который выполняет всю работу с основными данными.Периодически он вызывает save: в фоновом контексте

  • Как только все будет сделано, удалите наблюдателя из центра уведомлений

Описанный метод можно найти ниже.

Все работает как положено.Я могу передать блоки, которые добавляют данные, обновляют данные или удаляют данные. Но : я получаю следующую ошибку, когда закрываю приложение с некоторыми данными, заново открываю его и затем пытаюсь удалить данные в фоновом режиме:

CoreData: ошибка: серьезнаяОшибка приложения.Исключение было получено от делегата NSFetchedResultsController во время вызова -controllerDidChangeContent :.CoreData не может выполнить ошибку для [...]

Как видно из ошибки, я использую NSFetchedResultsController для отображения данных.Кеш контроллера установлен на nil.

Есть предложения как это исправить?


Вот соответствующий код.Обратите внимание, что я использую ARC.

FJCoreDataBackgroundBlock определяется следующим образом:

typedef void(^FJCoreDataBackgroundBlock)(NSManagedObjectContext *backgroundContext);

Метод выполнения нескольких базовых данных в фоновом режиме

- (void)performBlockInBackground:(FJCoreDataBackgroundBlock)block
{
    [FJSharedOperationQueue addOperationWithBlock:^{

        self.managedObjectContext = [[NSManagedObjectContext alloc] init];
        [_managedObjectContext setUndoManager:nil];
        [_managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];

        [self setupNotificationCenterObserverForContext:_managedObjectContext];

        FJCoreDataBackgroundBlock backgroundBlock = [block copy];
        backgroundBlock(self.managedObjectContext);

        [self saveBackgroundContext];
        [self saveMainContext];
        [self removeNotificationCenterObserver];
    }];
}

Реализация FJSharedOperationQueue:

+ (NSOperationQueue *)sharedQueue
{
    static dispatch_once_t predicate = 0;

    __strong static NSOperationQueue *_sharedQueue = nil;

    dispatch_once(&predicate, ^{
        _sharedQueue = [[NSOperationQueue alloc] init];
        [_sharedQueue setMaxConcurrentOperationCount:1];
    });

    return _sharedQueue;
}

+ (void)addOperationWithBlock:(void (^)(void))block
{
    [[FJSharedOperationQueue sharedQueue] addOperationWithBlock:block];
}

1 Ответ

0 голосов
/ 30 января 2012

Теперь это странно: я перебираю строки кода в блоке, который удаляет объекты.Прежде чем это выглядело так:

FJCoreDataHelper *helper = [[FJCoreDataHelper alloc] initUsingMainManagedObjectContext:[self mainContext]];

[helper performBlockInBackground:^(NSManagedObjectContext *backgroundContext) {

    // [Fetch objets here...]

    // Delete:

    const int kSaveThreshold = 50;
    for (int card = 0, count = [allCards count]; card < count; card++)
    {
        [backgroundContext deleteObject:[allCards objectAtIndex:card]];

        if (card % kSaveThreshold == 0)
        {
            [helper saveBackgroundContext];
        }
    }
    }];

Чтобы исправить это, мне просто нужно было сохранить основной контекст после сохранения фонового контекста:

[helper performBlockInBackground:^(NSManagedObjectContext *backgroundContext) {

    // [Fetch objets here...]

    // Delete:

    const int kSaveThreshold = 50;
    for (int card = 0, count = [allCards count]; card < count; card++)
    {
        [backgroundContext deleteObject:[allCards objectAtIndex:card]];

        if (card % kSaveThreshold == 0)
        {
            [helper saveBackgroundContext];
            [helper saveMainContext];
        }
    }
    }];

Если я сохраню только фоновый контекст,это падает.Если я сначала сохраню основной контекст, он тоже вылетает.Я нахожу это странным, потому что я думал, что объединение фонового контекста с основным контекстом также сохранит основной контекст ...

...