UISearchResultsController在设备上崩溃(索引超出空数组的边界)

时间:2010-07-13 15:07:17

标签: iphone objective-c uisearchbar nsfetchedresultscontroller uisearchdisplaycontroller

我正在使用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;
}

这在模拟器中很有效。但是在设备上,当尝试显示searchResultsTableView时,它会在object = [[self filteredListContent] objectAtIndex:[indexPath row]];上从configureCell崩溃。我收到错误[NSMutableArray objectAtIndex:]: index 7 beyond bounds for empty array。始终索引7.我在这里缺少什么?

- UPDATE -

修正:翻转searchIsActive BOOL以启用searchDisplayControllerDidBeginSearch而不是searchDisplayControllerWillBeginSearchsearchDisplayControllerWillEndSearch而不是searchDisplayControllerDidEndSearch。这使得表不会尝试配置不存在的单元。不知道为什么模拟器没有抓住这个

2 个答案:

答案 0 :(得分:0)

如果它引用的数组是空的,那么如果你试图从空数组中填充tableview,那么索引是什么并不重要。

您的NSMutableArray filteredListContent是否已填充(即您是否从提取的结果控制器返回搜索结果)?您是否在filterContentForSearchText:

中检查了数组的内容

P.S。我喜欢你的风格...... BeerListTableViewCell:)

答案 1 :(得分:0)

在处理对现有应用的更新时遇到了完全相同的崩溃。代码几乎与原始海报完全相同,我的应用程序中唯一改变的是数据库。 没有代码更改

使用旧数据库时,搜索显示控制器开始搜索时不会调用表视图数据源方法。

使用新数据库,当搜索显示控制器开始搜索时,将调用表视图数据源方法 do

相同的核心数据实体,相同的数据库结构,相同的代码,相同的笔尖。模拟器或设备上的问题相同。