Próbowałem dodać prostą funkcję wyszukiwania do TableViewController w mojej aplikacji. Postępowałem zgodnie z poradnikiem Raya Wenderlicha. Mam tableView z danymi, dodałem pasek wyszukiwania + kontroler wyświetlacza w scenorysie, a potem mam ten kod:
#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;
}
Standardowe rzeczy, ale kiedy wpisuję tekst w pasku wyszukiwania, za każdym razem ulega awarii z tym błędem:
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'
Rozumiem, że w iOS 6 zmienił się system obsługi i usuwania z kolejki komórek, a także, że wyszukiwanie używa innego tableView, więc pomyślałem, że problem polega na tym, że wyszukiwanie tableView z przefiltrowanymi wynikami nie wie o komórce, więc wstawiłem to moim zdaniem
[self.searchDisplayController.searchResultsTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"BreedCell"];
I voila! Zadziałało ... Tylko przy pierwszym wyszukiwaniu. Jeśli wrócisz do oryginalnych wyników i ponownie rozpoczniesz wyszukiwanie, aplikacja ulegnie awarii z tym samym błędem. Pomyślałem o może dodaniu wszystkich
if(!cell){//init cell here};
stuff do metody cellForRow, ale czy nie jest to sprzeczne z całym celem posiadania metody dequeueReusableCellWithIdentifier: forIndexPath:? W każdym razie zgubiłem się. czego mi brakuje? Prosimy o pomoc. Z góry dziękuję za poświęcony czas (:
Alex.
dequeueReusableCellWithIdentifier:forIndexPath:
przezdequeueReusableCellWithIdentifier:
.Powodem, dla którego działało świetnie przy pierwszym uruchomieniu, ale potem uległo awarii, jeśli opuściłeś tabelę wyników i wróciłeś do kolejnego wyszukiwania, jest to, że kontroler wyświetlania wyszukiwania ładuje nowy za
UITableView
każdym razem, gdy wchodzisz w tryb wyszukiwania.Mówiąc tryb wyszukiwania, mam na myśli, że dotknąłeś pola tekstowego i zacząłeś pisać, w którym momencie generowany jest widok tabeli w celu wyświetlenia wyników, wychodząc z tego trybu, który osiągnięto, naciskając przycisk anulowania. Gdy dotkniesz pola tekstowego po raz drugi i zaczniesz pisać ponownie - oznacza to wejście w „tryb wyszukiwania” po raz drugi.
Aby uniknąć awarii, należy zarejestrować klasę komórki dla widoku tabeli, która ma być używana w
searchDisplayController:didLoadSearchResultsTableView:
metodzie delegata (zUISearchDisplayDelegate
) lub wviewDidLoad
metodzie kontrolerów .Następująco:
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView { [tableView registerClass:[DPContentTableCell class] forCellReuseIdentifier:cellIdentifier]; [tableView registerClass:[DPEmptyContentTableCell class] forCellReuseIdentifier:emptyCellIdentifier]; }
Zaskoczyło mnie to, ponieważ na iOS 7 ... widok tabeli jest ponownie używany. Możesz więc zarejestrować zajęcia,
viewDidLoad
jeśli wolisz. Ze względu na dziedzictwo zachowam swoją rejestrację w metodzie delegowania, o której wspomniałem.źródło
Po wyszukaniu „tableView” metody cellForRowAtIndexPath wydaje się nie być instancją zdefiniowanej tabeli. Możesz więc użyć wystąpienia tabeli, która definiuje komórkę. Zamiast:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
Posługiwać się:
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
(Nie używaj tableView metody cellForRowAtIndexPath, użyj self.tableView ).
źródło
Zdejmij komórkę z kolejki bez użycia parametru „indexPath”, a jeśli uzyskasz element zerowy, musisz go przydzielić ręcznie.
- (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; }
Próba użycia self.tableView do usunięcia z kolejki komórki może spowodować awarie, jeśli masz podzieloną listę główną i zwykłą listę wyszukiwania. Ten kod zamiast tego działa w każdej sytuacji.
źródło
Kiedy miałem ten problem, rozwiązaniem była zamiana
tableView
dequeueReusableCellWithIdentifier: @yourcell naself.tableView
źródło
Pracuję również nad tym samouczkiem. Domyślny TableViewController ma „forIndexPath” iw jego przykładzie nie istnieje. Po usunięciu tego wyszukiwanie działa.
//Default code UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; //Replace with UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
źródło
dla Swift 3 wystarczy dodać siebie:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = self.tableView.dequeueReusableCell(withIdentifier: "yourCell", for: indexPath) as! YourCell ... }
źródło