在 UITableViewController 中使用 UISearchDisplayController 时断言失败

我一直试图在我的应用程序中向 TableViewController 添加简单的搜索功能。我遵循了雷 · 温德利希的教程。我有一个带有一些数据的 tableView,我在故事板中添加了搜索栏 + 显示控制器,然后我有这样的代码:

#pragma mark - Table View
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BreedCell" forIndexPath:indexPath];


//Create PetBreed Object and return corresponding breed from corresponding array
PetBreed *petBreed = nil;


if(tableView == self.searchDisplayController.searchResultsTableView)
petBreed = [_filteredBreedsArray objectAtIndex:indexPath.row];
else
petBreed = [_breedsArray objectAtIndex:indexPath.row];


cell.accessoryType  = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.text = petBreed.name;


return cell;
}


#pragma mark - Search
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[_filteredBreedsArray removeAllObjects];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.name contains[c] %@",searchString];
_filteredBreedsArray = [[_breedsArray filteredArrayUsingPredicate:predicate] mutableCopy];


return YES;
}


-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
// Tells the table data source to reload when scope bar selection changes


[_filteredBreedsArray removeAllObjects];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.name contains[c] %@",self.searchDisplayController.searchBar.text];
_filteredBreedsArray = [[_breedsArray filteredArrayUsingPredicate:predicate] mutableCopy];
return YES;
}

标准的东西,但是当我在搜索栏输入文本时,它每次都会崩溃,出现这样的错误:

2013-01-07 19:47:07.330 FindFeedo[3206:c07] *** Assertion failure in -[UISearchResultsTableView dequeueReusableCellWithIdentifier:forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2372/UITableView.m:4460
2013-01-07 19:47:07.330 FindFeedo[3206:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unable to dequeue a cell with identifier BreedCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'

我知道在 iOS6中单元格的处理和排队系统发生了变化,而且搜索使用了不同的 tableView,所以我认为问题在于带有过滤结果的 search tableView 不知道单元格,所以我把这个放在 viewDidLoad 中:

[self.searchDisplayController.searchResultsTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"BreedCell"];

瞧!成功了... 只是你第一次搜索的时候。如果你回到最初的搜索结果,再次搜索,应用程序崩溃,同样的错误。我想也许可以加上

if(!cell){//init cell here};

但是这不是违背了使用 dequeue eReusableCellWithIdentifier: forIndexPath: method 的整个目的吗?不管怎样,我迷路了。我错过了什么?救命啊。提前感谢你所有的时间(:

亚历克斯。

18298 次浏览

尝试在 dequeue eReusableCellWithIdentifier 中使用 self. tableView 代替 tableView:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"BreedCell"];


//Create PetBreed Object and return corresponding breed from corresponding array
PetBreed *petBreed = nil;


if(tableView == self.searchDisplayController.searchResultsTableView)
petBreed = [_filteredBreedsArray objectAtIndex:indexPath.row];
else
petBreed = [_breedsArray objectAtIndex:indexPath.row];


cell.accessoryType  = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.text = petBreed.name;


return cell;
}

这个代码运行得很好

注意

如果有自定义高度单元格,请不要使用

[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

用这个代替

[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];

取消单元格的队列,而不使用“ indexPath”,如果您获得一个 nil 元素,则必须手动分配它。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"YourCellId"];
if (!cell)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"YourCellId"];


// fill your cell object with useful stuff :)


return cell;
}

尝试使用 self. tableView 取队列单元格可能会导致当您有一个分段主列表和一个普通搜索列表时崩溃。 此代码可以在任何情况下工作。

为什么它在第一次运行时工作得很好,但是当你退出搜索结果表并返回进行另一次搜索时却崩溃了呢? 这是因为每次你进入搜索模式时,搜索显示控制器都会加载一个新的 UITableView

通过搜索模式,我的意思是,您已经点击文本字段并开始输入,此时将生成一个表视图来显示结果,退出通过点击取消按钮实现的这种模式。当您第二次点击文本字段,并开始再次输入-这是第二次进入“搜索模式”。

因此,为了避免崩溃,您应该为表视图注册单元格类,以便在 searchDisplayController:didLoadSearchResultsTableView:委托方法(来自 UISearchDisplayDelegate)中使用,而不是在控制器 viewDidLoad方法中使用。

如下:

- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView
{
[tableView registerClass:[DPContentTableCell class] forCellReuseIdentifier:cellIdentifier];
[tableView registerClass:[DPEmptyContentTableCell class] forCellReuseIdentifier:emptyCellIdentifier];
}

这让我大吃一惊,因为在 iOS7上... 表格视图被重用了。所以如果你愿意,你可以在 viewDidLoad中注册这个类。出于遗留问题的考虑,我将把注册保留在前面提到的 Committee 方法中。

我也在做那个教程。默认的 TableViewController 具有“ forIndexPath”,在他的示例中它不存在。一旦我移除它,搜索工作。

//Default code
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];


//Replace with
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

搜索之后,cellForRowAtIndexPath 方法的“ tableView”似乎不是您定义的 Table 的实例。因此,可以使用定义单元格的表的实例。而不是:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

用途:

UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

(不要使用 cellForRowAtIndexPath 方法的 TableView,使用 Self. tableView。)

当我遇到这个问题时,解决方案是用 self.tableView替换 tableView dequeue eReusableCellWithIdentifier:@yourcell

对于 Swift 3,你只需要加上 self:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = self.tableView.dequeueReusableCell(withIdentifier: "yourCell", for: indexPath) as! YourCell


...
}