Подтвердить что ты не робот

NSFetchedResultsController добавляет строку или раздел

У меня есть UITableView, заполненный стандартным NSFetchedResultsController. Однако я хотел бы добавить строку или раздел (строка предпочтительно, но либо будет работать нормально).

Единственный способ, с помощью которого я могу сейчас это сделать, - это переписать все NSIndexPath вручную при работе с разделом/строками, связанными с данными из NSFetchedResultsController, чтобы обмануть его в виде раздела с индексом 0 и начиная с строки с индексом 0. Однако это похоже на действительно плохую идею, которая бы быстро запуталась, поэтому я бы предпочел избежать этого.

Хороший пример этого будет в официальном приложении Twitter, когда вы начнете его впервые, и я прошу вас добавить некоторых людей из списка ваших друзей.

Screenshot of Twitter app's suggestions page, with the relevant sections highlighted

Красный раздел - это в значительной степени то, что я хотел бы достичь, а желтый раздел, который я предполагаю, является результатом NSFetchedResultsController в том же разделе (хотя с их собственным стилем это может быть отдельный раздел.)

4b9b3361

Ответ 1

Это можно сделать довольно чистым способом.

Я предполагаю, что вы начинаете со стандартного представления таблицы со стандартным NSFetchResultsController, который использует образец кода Apple.

Сначала вам понадобятся две служебные функции:

- (NSIndexPath *)mapIndexPathFromFetchResultsController:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0)
        indexPath = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section];

    return indexPath;
}

- (NSIndexPath *)mapIndexPathToFetchResultsController:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0)
        indexPath = [NSIndexPath indexPathForRow:indexPath.row-1 inSection:indexPath.section];

    return indexPath;
}

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

Затем нам нужно создать дополнительную ячейку:

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

    if (indexPath.section == 0 && indexPath.row == 0)
    {
        UITableViewCell *cell;
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
        cell.selectionStyle = UITableViewCellSelectionStyleGray;
        cell.textLabel.text = NSLocalizedString(@"Extra cell text", nil);

        return cell;
    }

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

    [self configureCell:cell atIndexPath:indexPath];

    return cell;
}

убедитесь, что мы настроили его правильно (configurecell будет вызываться только для ячеек из контроллера результатов выборки):

// the indexPath parameter here is the one for the table; ie. it offset from the fetched result controller indexes
- (void)configureCell:(SyncListViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    indexPath = [self mapIndexPathToFetchResultsController:indexPath];

    id *obj = [fetchedResultsController objectAtIndexPath:indexPath];
    <... perform normal cell setup ...>
}

и сообщите, что он существует:

- (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];
    }

    if (section == 0)
        numberOfRows++;

    return numberOfRows;
}

и ответьте на выбор:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];

    if (indexPath.section == 0 && indexPath.row == 0)
    {
        [self doExtraAction];
        return;
    }

    ... deal with selection for other cells ...

а затем переназначьте все обновления, которые мы получаем от контроллера результатов:

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

    indexPath = [self mapIndexPathFromFetchResultsController:indexPath];
    newIndexPath = [self mapIndexPathFromFetchResultsController:newIndexPath];

    switch(type) {
        ... handle as normal ...

Ответ 2

Я понимаю вашу озабоченность сложностью, но на самом деле это просто добавление от 1 до numberOfRowsInSection: и добавление 1 к indexPath.row в cellForRowAtIndexPath: (помимо добавления кода для строки 0).

Другое решение не должно быть очень сложным, чтобы стать еще более громоздким.

При этом кажется, что "заголовок", который вы предлагаете, является типичным кандидатом для заголовка раздела.