Ошибка утверждения при использовании UISearchDisplayController в UITableViewController



Я пытался добавить простую функцию поиска в 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'


Я понимаю, что в iOS 6 система обработки и удаления очереди для ячеек изменилась, и кроме того, что поиск использует другой tableView, поэтому я думал, что проблема в том, что поиск tableView с отфильтрованными результатами не знал о ячейке, поэтому я поместил это в свой viewDidLoad:



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


и вуаля! Это сработало... Только при первом поиске. Если вы вернетесь к исходным результатам и снова выполните поиск, приложение завершит работу с той же ошибкой. Я думал о том, может быть, добавив все



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


материал для метода cellForRow, но не идет ли это против вся цель иметь dequeueReusableCellWithIdentifier:forIndexPath: метод? В любом случае, я заблудился. Чего мне не хватает? Помогите, пожалуйста. Заранее спасибо за все ваше время (:



Алекс.

493   7  

7 ответов:

попробуйте использовать self.tableView вместо tableView в dequeueReusableCellWithIdentifier:

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

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

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

поэтому, чтобы избежать сбоя, вы должны зарегистрировать класс ячейки для табличного представления для использования в searchDisplayController:didLoadSearchResultsTableView: метод (с UISearchDisplayDelegate) вместо того, чтобы в ваших контроллерах viewDidLoad метод.

следующим образом:

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

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

после поиска, 'tableView' метода cellForRowAtIndexPath кажется не экземпляр таблицы, которую вы определяете. Таким образом, вы можете использовать экземпляр таблицы, которая определяет ячейку. Вместо:

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

использование:

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

(Не используйте tableView метода cellForRowAtIndexPath, используйте self.tableView.)

Dequeue ячейку без использования "indexPath" и в случае получения нулевого элемента, вы должны выделить его вручную.

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

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

когда у меня была эта проблема, решение заменяло tableView dequeueReusableCellWithIdentifier:@yourcell с self.tableView

Я работаю над этим учебником. По умолчанию TableViewController имеет "forIndexPath" и в его примере он не существует. Как только я удалил его, поиск работает.

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

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

для swift 3 вам просто нужно добавить self:

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

    ...
}

Comments

    Ничего не найдено.