Первый ряд не отображается после операции вставки, сохраните мои волосы - PullRequest
1 голос
/ 07 июля 2010

У меня тут ситуация, и я теряю волосы ...

Очень простое приложение, управляемое базовыми данными, которое имеет контроллер табличного представления с кнопкой навигации добавления. Это очень похоже на образец рецептов, с парой различий

  • В модели имеется только один объект с двумя атрибутами
  • Ячейка в главной таблице не настроена, используется текстовая метка по умолчанию

С основной частью данных все в порядке, поскольку новая запись добавляется в базовое хранилище и извлекается с использованием контроллера полученных результатов. Проблема возникает, когда я добавляю новый элемент, который будет размещен в верхней части списка. Это может быть, например, новый элемент в пустом списке или элемент с порядком сортировки, поднимающий его наверх. Элемент, который находится сверху, не виден! Ячейка там с текстовой меткой nil, однако я ясно видел, что извлеченный контроллер результатов выдает уведомление об обновлении, и я настроил ячейку, обновляя ее новым текстом.

Единственный способ сделать эту ячейку для отображения - это прокрутить таблицу данных, чтобы вызвать cellForRowAtIndexPath, затем текст элемента обновится. Я добавляю еще один элемент, который будет помещен сверху, снова текст нового элемента не виден. Я добавляю элемент, который будет располагаться внизу - нет проблем, текст в ячейке виден. Также изначально, когда я просто запускаю приложение, проблем нет, все элементы видны.

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

UPD:

- (void)configureCell:(UITableViewCell *)cell 
        atIndexPath:(NSIndexPath *)indexPath 
{
    Word* word = (Word*)[fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = word.word;
    printf("configureCell: %d : \"%s\"\n", indexPath.row,
           [word.word cStringUsingEncoding:NSASCIIStringEncoding]);
}

- (UITableViewCell *)tableView:(UITableView *)tableView
                     cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView
                      dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) 
    {
        cell = [[[UITableViewCell alloc]
                              initWithStyle:UITableViewCellStyleDefault
                              reuseIdentifier:CellIdentifier] autorelease];
    }

    [self configureCell:cell atIndexPath:indexPath];

    return cell;
}

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller 
{
[self.tableView beginUpdates];
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller 
{
[self.tableView endUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.tableView;

switch(type) {
          case NSFetchedResultsChangeInsert:
        printf("didChangeObjectAtRow: %d: insert\n", newIndexPath.row);
        [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;

    case NSFetchedResultsChangeDelete:
        printf("didChangeObjectAtRow: %d : delete\n", indexPath.row);
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;

    case NSFetchedResultsChangeUpdate:
        printf("didChangeObjectAtRow: %d : update\n", indexPath.row);
        [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
        break;

    case NSFetchedResultsChangeMove:
        printf("didChangeObjectAtRow: %d / %d : move\n", indexPath.row, newIndexPath.row);
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;
}
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{
        NSInteger count = [[fetchedResultsController sections] count];

        if (count == 0) 
        {
            count = 1;
        }
printf("number of sections: %d\n", count);
return count;
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
        {
        NSInteger numberOfRows = 0;
        if ([[fetchedResultsController sections] count] > 0) 
{
    id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
    numberOfRows = [sectionInfo numberOfObjects];
}

printf("number of rows in sections: %d is %d\n", section, numberOfRows);
return numberOfRows;
}

- (NSFetchedResultsController*)fetchedResultsController
{
if(fetchedResultsController != nil)
    return fetchedResultsController;

// This is autoreleased as the name implies
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Word" inManagedObjectContext:managedObjectContext];

NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];

NSSortDescriptor* sortByWordDescriptor = [[NSSortDescriptor alloc] initWithKey:@"word" ascending:YES];
NSArray* sortArray = [[NSArray alloc] initWithObjects:sortByWordDescriptor, nil];
[fetchRequest setSortDescriptors:sortArray];


NSFetchedResultsController* controller = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Hmm"];
controller.delegate = self;
self.fetchedResultsController = controller;

[fetchRequest release];
[sortByWordDescriptor release];
[sortArray release];
[controller release];

return fetchedResultsController;
}

- (void) add:(id)sender
{
WordzWordEditView *wordEditViewController = [[WordzWordEditView alloc] initWithNibName:@"WordzWordEditView" bundle:nil];
wordEditViewController.delegate = self;

Word* word = [NSEntityDescription insertNewObjectForEntityForName:@"Word" inManagedObjectContext:self.managedObjectContext];
wordEditViewController.word = word;

UINavigationController *editWordNavigationController = [[UINavigationController alloc] initWithRootViewController:wordEditViewController];

[self presentModalViewController:editWordNavigationController animated:YES];

[wordEditViewController release];
[editWordNavigationController release];

}

UPD: вывод

controllerWillChangeContent
didChangeObjectAtRow: 0: insert
controllerDidChangeContent
number of sections: 1
number of sections: 1
number of rows in sections: 0 is 2
cellForRowAtIndexPath: 0
configureCell: 0 : "(null)"
post configuring: "(null)"
controllerWillChangeContent
configureCell: 0 : "asd"
didChangeObjectAtRow: 0 : update with 'asd'
controllerDidChangeContent
number of sections: 1
number of sections: 1
number of rows in sections: 0 is 2

Ответы [ 6 ]

1 голос
/ 23 сентября 2011

Вы пробовали [self.tableView reloadData] в -viewWillAppear: анимированный? У меня была похожая проблема с первым рядом. Но после того, как я добавлю это, все в порядке.

1 голос
/ 21 марта 2011

Я бы изменил:

case NSFetchedResultsChangeUpdate:
    printf("didChangeObjectAtRow: %d : update\n", indexPath.row);
    [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
    break;

на:

case NSFetchedResultsChangeUpdate:
    printf("didChangeObjectAtRow: %d : update\n", indexPath.row);
    [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
    break;

Я не уверен, почему приложение рецептов отменяет это поведение, так как configureCell все еще вызывается.

0 голосов
/ 16 июля 2012

У меня была похожая проблема, я начал искать решение и наткнулся на этот старый пост. Я не видел, что проблема была решена, поэтому я посмотрел на то, что вызывалось в методе

  • (void) контроллер: (NSFetchedResultsController *) контроллер didChangeObject: (id) anObject atIndexPath: (NSIndexPath *) indexPath forChangeType: (NSFetchedResultsChangeType) type newIndexPath: (NSIndexPath *) newIndexPath

Похоже, что когда вы возвращаетесь из детального контроллера, вместо выполнения вставки он фактически выполняет обновление. Это связано с тем, что приложение основных рецептов данных выполняет создание элемента, добавляемого в базу данных, до вызова подробного контроллера.

Добавив следующую строку в NSFetchedResultsChangeUpdate, я смог отобразить первую строку

        [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
0 голосов
/ 08 июля 2010

Некоторые наблюдения:

Эта строка в методе действия:

Word* word = [NSEntityDescription insertNewObjectForEntityForName:@"Word" inManagedObjectContext:self.managedObjectContext];

... запускает:

case NSFetchedResultsChangeInsert:
    printf("didChangeObjectAtRow: %d: insert\n", newIndexPath.row);
    [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
    break;

... до завершения диалога идо того, как Word managedObject имеет значение для своего атрибута word.Это создает пустую ячейку.

(Я зарегистрировал методы в приложении Recipie и получил:

2010-07-07 18:56:08.848 Recipes[53880:207] NSFetchedResultsChangeInsert:=<NSIndexPath 0x11286a0> 2 indexes [0, 0]
2010-07-07 18:56:22.872 Recipes[53880:207] NSFetchedResultsChangeUpdate=<NSIndexPath 0x11286a0> 2 indexes [0, 0]

... в последовательности.)

Интересно, что вы не регистрируете NSFetchedResultsChangeInsert.Что заставляет меня думать, что чего-то не хватает.Возможно, в вашей регистрации.

Я думаю, что проблема может быть вызвана использованием модального контроллера, используемого для изменения значения Word.word.Модальное представление не позволяет таблице реагировать на NSFetchedResultsChangeUpdate, когда это происходит, поэтому сохраняет начальное нулевое значение до тех пор, пока вы не выполните прокрутку, в результате чего она перезагрузит ячейку из контроллера выбранных результатов.Просто предположение.

Вы можете проверить, вставив объект Word, а затем изменив свойство word в коде без модального представления.Возможно, используйте таймер, чтобы немного задержаться.Если это работает, то это определенно модальное представление, вызывающее проблему.

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

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

Вы используете неверный тип. (ошибка копирования / вставки) Вы используете UITableViewCell в tableView:cellForRowatIndexPath

case NSFetchedResultsChangeUpdate:
    printf("didChangeObjectAtRow: %d : update\n", indexPath.row);
    [self configureCell:(RecipeTableViewCell *)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
    break;

Заменить:

[self configureCell:(RecipeTableViewCell *)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];

С:

[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
0 голосов
/ 07 июля 2010

Без исходного кода трудно точно определить, когда вы добавляете данные, вы звоните

– insertRowsAtIndexPaths:withRowAnimation:

Если вы позвоните [self.tableview reloadData] после добавления, появится ли оно

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