Error de aserción al usar UISearchDisplayController en UITableViewController


He estado tratando de agregar una funcionalidad de búsqueda simple a un TableViewController en mi aplicación. Seguí el tutorial de Ray Wenderlich. Tengo una vista de tabla con algunos datos, agregué la barra de búsqueda + controlador de pantalla en storyboard, 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;
    }

El material estándar, pero cuando introduzco 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 dequeueing para celdas cambió, y también que la búsqueda utiliza un diferente formato tableview, así que pensé que el problema era que la búsqueda en formato tableview con los resultados filtrados no sabía acerca de la célula, así que me puse esto en mi viewDidLoad:

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

Y voila! Funcionó... Solo la primera vez que busques. Si vuelve a los resultados originales y vuelve a buscar, la aplicación se bloquea con el mismo error. Pensé en tal vez añadir todos los

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

Cosas para el método cellForRow, pero eso no va en contra de todo el propósito de tener la dequeueReusableCellWithIdentifier: forIndexPath: method? De todos modos, estoy perdido. ¿Qué me estoy perdiendo? Ayuda, por favor. Gracias de antemano por todo su tiempo (:

Alex.

Author: Daniel, 2013-01-08

7 answers

Intenta usar self.tableView en lugar de tableView en 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;
}

Este código funciona bastante bien

Nota

Si tiene celdas de altura personalizadas, no use

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

Usa esto en su lugar

[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
 192
Author: FunkyKat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-24 11:40:19

La razón por la que funcionó muy bien en la primera ejecución, pero luego se bloqueó si salió de la tabla de resultados y regresó para otra búsqueda es porque el Controlador de Visualización de Búsqueda está cargando un nuevo UITableView cada vez que ingresa al modo de búsqueda.

Por modo de búsqueda quiero decir, has pulsado el campo de texto y has comenzado a escribir, en cuyo punto se genera una vista de tabla para mostrar los resultados, saliendo de este modo se logró pulsando el botón cancelar. Cuando toque el campo de texto la segunda vez y comience escribir de nuevo-esto es entrar en "modo de búsqueda" por segunda vez.

Por lo tanto, para evitar el bloqueo, debe registrar la clase de celda para la vista de tabla para usar en el método delegado searchDisplayController:didLoadSearchResultsTableView: (de UISearchDisplayDelegate) en lugar de en su método controllers viewDidLoad.

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 reutilizan. Así que puedes registrar la clase en viewDidLoad si lo prefieres. Por el bien del legado, mantendré mi registro en el delegado método que mencioné.

 14
Author: Daniel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-14 09:48:25

Después de buscar, 'tableView' del método cellForRowAtIndexPath no parece una instancia de la Tabla que defina. Por lo tanto, puede utilizar una instancia de una tabla que define la celda. En lugar de:

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

Uso:

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

(No use el método tableView de cellForRowAtIndexPath, use self.tableView .)

 11
Author: aqubi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-12 18:54:32

Dequeue la celda sin usar el 'indexPath' y en caso de obtener un elemento nil, 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;
}

Tratando de usar el yo.tableView for dequeue la celda puede causar bloqueos cuando tiene una lista principal seccionada y una lista de búsqueda simple. Este código funciona en cualquier situación.

 3
Author: skaman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-24 14:51:06

Cuando tuve este problema, la solución fue reemplazar tableView dequeueReusableCellWithIdentifier:@yourcell por self.tableView

 3
Author: glorio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-02 20:50:32

Estoy trabajando en ese tutorial también. El controlador TableViewController predeterminado tiene "forIndexPath" y en su ejemplo no existe. Una vez que lo quité, la búsqueda funciona.

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

//Replace with
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
 2
Author: sonicbabbler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-10 15:49:35

Para swift 3 solo necesita agregar self:

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

    ...
}
 1
Author: Eugene Gordin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-18 17:43:35