He intentado agregar una funcionalidad de búsqueda simple a un TableViewController en mi aplicación. Seguí el tutorial de Ray Wenderlich. Tengo un tableView con algunos datos, agregué la barra de búsqueda + el controlador de pantalla en el guión gráfico, y luego tengo este código:
#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;
}
Las cosas estándar, pero cuando ingreso texto en la barra de búsqueda, se bloquea cada vez con este error:
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'
Entiendo que en iOS 6 el sistema de manejo y eliminación de la cola de las celdas cambió, y también que la búsqueda usa una vista de tabla diferente, así que pensé que el problema era que la vista de tabla de búsqueda con los resultados filtrados no conocía la celda, así que puse esto en mi opiniónDidLoad:
[self.searchDisplayController.searchResultsTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"BreedCell"];
¡Y voilá! Funcionó ... Sólo la primera vez que buscas. Si vuelve a los resultados originales y vuelve a buscar, la aplicación se bloquea con el mismo error. Pensé en agregar todos los
if(!cell){//init cell here};
cosas al método cellForRow, pero ¿no va eso en contra del propósito de tener el método dequeueReusableCellWithIdentifier: forIndexPath:? De todos modos, estoy perdido. ¿Qué me estoy perdiendo? Ayuda por favor. Gracias de antemano por todo su tiempo (:
Alex.
dequeueReusableCellWithIdentifier:forIndexPath:
pordequeueReusableCellWithIdentifier:
.La razón por la que funcionó muy bien en la primera ejecución, pero luego se bloqueó si salía de la tabla de resultados y regresaba para otra búsqueda es porque el controlador de pantalla de búsqueda está cargando uno nuevo
UITableView
cada vez que ingresa al modo de búsqueda.Por modo de búsqueda, quiero decir, ha tocado el campo de texto y ha comenzado a escribir, momento en el que se genera una vista de tabla para mostrar los resultados, saliendo de este modo que logró presionando el botón cancelar. Cuando toca el campo de texto por segunda vez y comienza a escribir nuevamente, esto es ingresar al "modo de búsqueda" por segunda vez.
Entonces, para evitar el bloqueo, debe registrar la clase de celda para que la vista de tabla use en el
searchDisplayController:didLoadSearchResultsTableView:
método delegado (desdeUISearchDisplayDelegate
) en lugar de en elviewDidLoad
método de los controladores .Como sigue:
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView { [tableView registerClass:[DPContentTableCell class] forCellReuseIdentifier:cellIdentifier]; [tableView registerClass:[DPEmptyContentTableCell class] forCellReuseIdentifier:emptyCellIdentifier]; }
Esto me tomó por sorpresa porque en iOS 7 ... la vista de tabla se está reutilizando. Para que puedas inscribirte en la clase
viewDidLoad
si lo prefieres. Por el bien de la herencia, mantendré mi registro en el método de delegado que mencioné.fuente
Después de buscar, 'tableView' del método cellForRowAtIndexPath parece no ser una instancia de la Tabla que usted define. Entonces, puede usar una instancia de una tabla que define la celda. En vez de:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
Utilizar:
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
(No use el método tableView de cellForRowAtIndexPath, use self.tableView ).
fuente
Quite la celda sin usar el 'indexPath' y en caso de que obtenga un elemento nulo, debe asignarlo manualmente.
- (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; }
Intentar usar self.tableView para quitar la cola de la celda puede causar bloqueos cuando tiene una lista principal seccionada y una lista de búsqueda simple. En cambio, este código funciona en cualquier situación.
fuente
Cuando tuve este problema, la solución fue reemplazar
tableView
dequeueReusableCellWithIdentifier: @yourcell conself.tableView
fuente
También estoy trabajando en ese tutorial. El TableViewController predeterminado tiene "forIndexPath" y en su ejemplo no existe. Una vez que lo eliminé, la búsqueda funciona.
//Default code UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; //Replace with UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
fuente
para swift 3 solo necesita agregar uno mismo:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = self.tableView.dequeueReusableCell(withIdentifier: "yourCell", for: indexPath) as! YourCell ... }
fuente