NSFetchedResultsController не отображает изменения из фонового потока - PullRequest
4 голосов
/ 03 июля 2011

Мое приложение использует NSFetchedResultsController, связанный с хранилищем базовых данных, и до сих пор оно работало хорошо, но сейчас я пытаюсь сделать код обновления асинхронным, и у меня возникают проблемы. Я создал подкласс NSOperation для выполнения своих обновлений и успешно добавляю этот новый объект в NSOperationQueue. Код обновлений выполняется так, как я ожидал, и я проверил это с помощью журналов отладки и проверки хранилища SQLite после его запуска.

Проблема в том, что после завершения моей фоновой операции новые (или обновленные) элементы не отображаются в моем UITableView. Исходя из моего ограниченного понимания, я считаю, что мне нужно уведомить основной managedObjectContext о том, что произошли изменения, чтобы их можно было объединить. Мое уведомление запускается, но новые элементы в табличном представлении не появляются. Если я остановлю приложение и перезапущу его, объекты появятся в табличном представлении, что наводит меня на мысль, что они успешно вставляются в основное хранилище данных, но не объединяются в managedObjectContext, используемый в основном потоке.

Я включил образец методов init, main и уведомлений моей операции. Я упускаю что-то важное или, может быть, поступаю неправильно? Любая помощь будет принята с благодарностью.

- (id)initWithDelegate:(AppDelegate *)theDelegate
{
    if (!(self = [super init])) return nil;
    delegate = theDelegate;
    return self;
}

- (void)main
{
    [self setUpdateContext:[self managedObjectContext]];
    NSManagedObjectContext *mainMOC = [self newContextToMainStore];
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    [center addObserver:self 
               selector:@selector(contextDidSave:) 
                   name:NSManagedObjectContextDidSaveNotification 
                 object:updateContext];
    [self setMainContext:mainMOC];

    // Create/update objects with mainContext.

    NSError *error = nil;
    if (![[self mainContext] save:&error]) {
        DLog(@"Error saving event to CoreData store");
    }
    DLog(@"Core Data context saved");
}


- (void)contextDidSave:(NSNotification*)notification
{
    DLog(@"Notification fired.");
    SEL selector = @selector(mergeChangesFromContextDidSaveNotification:);
    [[delegate managedObjectContext] performSelectorOnMainThread:selector
                                                      withObject:notification
                                                   waitUntilDone:YES]; 
}

Во время отладки я исследовал объект notification, который отправляется в contextDidSave:, и он, кажется, содержит все элементы, которые были добавлены (отрывок ниже). Это продолжает заставлять меня думать, что вставки / обновления происходят правильно, но каким-то образом объединение не запускается.

NSConcreteNotification 0x6b7b0b0 {name = NSManagingContextDidSaveChangesNotification; object = <NSManagedObjectContext: 0x5e8ab30>; userInfo = {
inserted = "{(\n    <GCTeam: 0x6b77290> (entity: GCTeam; id: 0xdc5ea10 <x-coredata://F4091BAE-4B47-4F3A-A008-B6A35D7AB196/GCTeam/p1> ; data: {\n    changed = 

Ответы [ 4 ]

0 голосов
/ 09 сентября 2011

Я столкнулся с подобной проблемой в симуляторе. Я начал процесс обновления при переходе от корневой таблицы к выбранной папке. Процесс обновления будет обновлять CoreData с веб-сервера, сохранять, затем объединять, но данные не отображаются. Если бы я пролистывал туда-сюда пару раз, он в конечном итоге появлялся, и один раз работал как по маслу (но я так и не смог повторить этот идеальный пробег). Это натолкнуло меня на мысль, что, возможно, это проблема синхронизации потоков / событий в симуляторе, когда таблица обновляется слишком быстро или уведомления просто не ставятся в очередь или что-то в этом роде. Я решил попробовать запустить в Instruments, чтобы посмотреть, смогу ли я точно определить проблему (все CoreData, CPU Monitor, утечки, распределения, состояния потоков, диспетчеризация и пара других). Каждый раз, когда я делал «первый запуск» с чистого листа, с тех пор он работал отлично. Может быть, инструменты замедляют его достаточно?

В конечном итоге мне нужно провести тестирование на устройстве, чтобы получить точный тест, и если проблема не исчезнет, ​​я попробую ваше решение в принятом ответе (чтобы создать базу данных sql-lite db для загрузки).

0 голосов
/ 03 июля 2011

В зависимости от того, что вы делаете, вы можете поступить неправильно.

В большинстве случаев вы можете просто назначить делегата, используя NSFetchedResultsControllerDelegate . Вы предоставляете реализацию для одного из методов, указанных в "responsedingToChanges", в зависимости от ваших потребностей, а затем отправляете tableView сообщение reloadData.

0 голосов
/ 07 июля 2011

Ответ оказался не связанным с опубликованным кодом, который работал, как я ожидал.По причинам, в которых я до сих пор не совсем уверен, это было связано с первым запуском приложения.Когда я попытался запустить операцию обновления при запуске после создания основного хранилища данных, оно работало как положено.Я решил проблему, предварительно загрузив версию базы данных sqlite в приложение, чтобы при первом запуске не требовалось создавать пустое хранилище.Хотелось бы я понять , почему это решило проблему, но я планировал сделать это в любом случае.Я оставляю это здесь в надежде, что кто-то еще найдет это полезным и не потеряет столько времени, сколько я потратил на это.

0 голосов
/ 03 июля 2011

Метод, который получает ваше уведомление, должен действительно уведомить ваш контекст, вы можете попробовать что-то вроде этого, что я и делаю в своем приложении:

 - (void)updateTable:(NSNotification *)saveNotification
  {
    if (fetchedResultsController == nil)
    {
       NSError *error;
    if (![[self fetchedResultsController] performFetch:&error]) {
    //Update to handle the error appropriately.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);  // Fail
    }       
}
else
{
    NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
    // Merging changes causes the fetched results controller to update its results
    [context mergeChangesFromContextDidSaveNotification:saveNotification];
    // Reload your table view data  
    [self.tableView reloadData];
}
}

Надеюсь, что это поможет.

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