Сбой UISearchResultsController на устройстве (индекс за пределами для пустого массива) - PullRequest
2 голосов
/ 13 июля 2010

Я использую UISearchResultsController для фильтрации данных из fetchedResultsController. Вот соответствующий код:

В RootVieweController.h:

@interface RootViewController : UITableViewController <NSFetchedResultsControllerDelegate, AdditionViewControllerDelegate, UISearchBarDelegate, UISearchDisplayDelegate> {

    NSArray *filteredListContent;   
    NSString *savedSearchTerm;
    NSInteger savedScopeButtonIndex;
    BOOL searchIsActive;
}
@property (nonatomic, retain) NSArray *filteredListContent;
@property (nonatomic, copy) NSString *savedSearchTerm;
@property (nonatomic) NSInteger savedScopeButtonIndex;
@property (nonatomic) BOOL searchIsActive;

В RootViewController.m:

-(void)viewDidLoad {
    [snip]
    UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 300, 40)];
    searchBar.delegate = self;
    searchBar.scopeButtonTitles = [NSArray arrayWithObjects:@"Scope 1", @"Scope 2", nil];
    [searchBar sizeToFit];
    searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
    self.tableView.tableHeaderView = searchBar;
    [searchBar release];
    [self.tableView setContentOffset:CGPointMake(0, 40)];

    UISearchDisplayController *searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
    [self performSelector:@selector(setSearchDisplayController:) withObject:searchDisplayController];

    [searchDisplayController setDelegate:self];
    [searchDisplayController setSearchResultsDataSource:self];
    [searchDisplayController setSearchResultsDelegate:self];
    [searchDisplayController release];

    self.filteredListContent = [NSMutableArray arrayWithCapacity:[[[self fetchedResultsController] fetchedObjects] count]];

    if (self.savedSearchTerm) {
        [self.searchDisplayController setActive:self.searchIsActive];
        [self.searchDisplayController.searchBar setSelectedScopeButtonIndex:self.savedScopeButtonIndex];
        [self.searchDisplayController.searchBar setText:savedSearchTerm];

        self.savedSearchTerm = nil;
    }
}

- (NSInteger)tableView:(UITableView *)theTableView numberOfRowsInSection:(NSInteger)section {
    // Return the number of rows in the section.
    if (theTableView == self.searchDisplayController.searchResultsTableView) {
        NSLog(@"Search Cells: %i", [self.filteredListContent count]);
        return [self.filteredListContent count];
    }
    id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
    NSLog(@"Normal cells: %i", [sectionInfo numberOfObjects]);
    return [sectionInfo numberOfObjects];
}

-(void)configureCell:(CustomTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
    //Called from cellForRowAtIndexPath

    Object *object = nil;
    if (self.searchIsActive) {
        object = [[self filteredListContent] objectAtIndex:[indexPath row]];
    } else {
        object = [fetchedResultsController objectAtIndexPath:indexPath];
    }

    [snip]
}


#pragma mark -
#pragma mark Search functions

-(void)filterContentForSearchText:(NSString *)searchText scope:(NSString *)scope {
    if ([scope isEqualToString:@"Scope 1"]) {
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"scope1 BEGINSWITH[cd] %@", searchText];
        self.filteredListContent = [[[self fetchedResultsController] fetchedObjects] filteredArrayUsingPredicate:predicate];
    } else {
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"scope2 BEGINSWITH[cd] %@", searchText];
        self.filteredListContent = [[[self fetchedResultsController]fetchedObjects] filteredArrayUsingPredicate:predicate];
    }
}

#pragma mark -
#pragma mark UISearchDisplayController Delegate Methods

- (void)searchDisplayController:(UISearchDisplayController *)controller willShowSearchResultsTableView:(UITableView *)theTableView {
    NSLog(@"Showing search results");
}

-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
    [self filterContentForSearchText:searchString scope:
     [[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:
      [self.searchDisplayController.searchBar selectedScopeButtonIndex]]];

    NSLog(@"Reloading for string");

    return YES;
}

-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
    [self filterContentForSearchText:[self.searchDisplayController.searchBar text] scope:
     [[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:searchOption]];

    NSLog(@"Reloading for scope");

    return YES;
}

-(void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
    self.searchDisplayController.searchResultsTableView.rowHeight = 55;
    self.searchIsActive = YES;
}

-(void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller {
    self.searchIsActive = NO;
}

Это прекрасно работает в симуляторе. Но на устройстве происходит сбой object = [[self filteredListContent] objectAtIndex:[indexPath row]]; из configureCell при попытке показать searchResultsTableView. Я получаю ошибку [NSMutableArray objectAtIndex:]: index 7 beyond bounds for empty array. Всегда индекс 7. Что мне здесь не хватает?

- ОБНОВЛЕНИЕ -

Исправлено: перевернул searchIsActive BOOL, чтобы включить searchDisplayControllerDidBeginSearch вместо searchDisplayControllerWillBeginSearch и searchDisplayControllerWillEndSearch вместо searchDisplayControllerDidEndSearch. Это удерживает таблицу от попыток настроить несуществующие ячейки. Понятия не имею, почему Симулятор не уловил это

Ответы [ 2 ]

0 голосов
/ 01 апреля 2011

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

В старой базе данных методы источника данных табличного представления не вызываются, когда контроллер отображения поиска начинает поиск.

С новой базой данных методы источника данных табличного представления do вызываются, когда контроллер отображения поиска начинает поиск.

Те же сущности базовых данных, та же структура базы данных, тот же код, те же кончики. Та же проблема в симуляторе или на устройстве.

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

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

Заполнен ли ваш NSMutableArray filteredListContent (т.е. вы возвращаете результаты поиска из контроллера извлеченных результатов)? Вы проверили содержимое массива в filterContentForSearchText:?

P.S. Мне нравится твой стиль ... BeerListTableViewCell:)

...