2014-10-29 15 views
6

Da iOS 8 ho riscontrato un problema strano con una visualizzazione tabella/configurazione UISearchBar e mi sono chiesto se altri hanno riscontrato un problema simile o possono indicare cosa, semmai, potrei sbagliarmi. L'ampia situazione:Problema di visualizzazione quando si utilizza UISearchBar con un controller di visualizzazione tabella e si passa a un'altra vista

  • Ho un UITableViewController con un'UISearchBar al suo interno, allestito nella app Storyboard
  • la vista tabella è una cella personalizzato, ancora una volta, allestito nella Storyboard
  • la selezione di un tavolo riga avvia un passaggio ad un'altra vista
  • eseguendo una ricerca, toccando una riga dai risultati della ricerca per passare all'altra vista, quindi tornando indietro di nuovo, si innesca vari problemi.

"I problemi" sono che se implemento cellForRowAtIndexPath come segue:

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

in altre parole specificando il percorso per dequeueReusableCellWithIdentifier, allora questo si traduce in un fallimento BAD_ACCESS o asserzione in iOS 8 (ma non iOS 7). Specificamente, un errore di asserzione o BAD_ACCESS si verifica quando si chiama dequeueReusableCellWithIdentifier nelle circostanze sopra menzionate, cioè quando, con una ricerca attiva, si passa da una delle celle nella tabella dei risultati a un'altra vista e quindi si segue nuovamente.

Ora, posso fermare l'errore che si verifica semplicemente chiamando:

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

senza passare nel indexPath. Questo funziona quindi senza errori in quanto tali, ma tornando alla visualizzazione tabella con i risultati di ricerca, si verifica uno strano problema di visualizzazione in cui sono posizionati sotto i risultati della ricerca, sembrano esserci i separatori di una tabella "fantasma", quasi come se il il sistema sta tentando di eseguire il rendering di una tabella direttamente sopra un'altra (ma cellForRowAtIndexPath non viene chiamato per ogni tabella, solo per la tabella dei risultati della ricerca come previsto).

Ho lo stesso problema se il seguito è collegato al controller di cella o di visualizzazione tabella (quindi in quest'ultimo caso, implemento didSelectRowAtIndexPath per attivare manualmente il seguito).

Quindi: (a) qualcuno può puntare a qualcosa che potrei fare male a causare questi problemi, o (b) puntare a un esempio di funzionamento di un controller di visualizzazione tabella con UISearchBar dove le celle della tabella seguono un altro vista? Sono sorpreso di avere così tanti problemi che l'implementazione di una tabella ricercabile con le viste di dettaglio deve essere una cosa comune e noiosa che le persone fanno sempre, no?

progetto di esempio esibendo l'iusse:http://www.javamex.com/DL/TableTest.zip

+0

Potete allegare un progetto di esempio per questo? Non posso riprodurlo – gabbler

+0

Carica un esempio: se carichi l'app, cerca ".geg" One ", quindi fai clic sull'icona delle informazioni sulla riga nei risultati della ricerca per andare alla visualizzazione dettagli, quindi torna indietro, inizia a eliminare il termine di ricerca" Uno "per inserire qualcos'altro, si otterrà il fallimento dell'asserzione. –

+0

Non riesco a riprodurre il secondo problema. Quello che ho fatto è stato mettere una condizione 'if (self.searchDisplayController.active) { cell = [self.tableView dequeueReusableCellWithIdentifier: @" MyCell "]; } else cell = [self.tableView dequeueReusableCellWithIdentifier: @ "MyCell" forIndexPath: indexPath]; 'Funziona bene – EridB

risposta

2

In realtà c'è niente di sbagliato con l'utilizzo di uno dei due metodi per annullare l'accodamento tuo cellulare per le principali tableView, anche se la variante indexPath sembra essere opzione preferita di Apple in questi giorni.

Per searchResultsTableView tuttavia, evitare di specificare indexPath poiché non è necessariamente valido per il controller di visualizzazione tableView. Cioè:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    MyTableViewCell *cell; 
    if ([tableView isEqual:self.searchDisplayController.searchResultsTableView]) { 
     cell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCell"]; 
    } else { 
     cell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCell" forIndexPath:indexPath]; 
    } 
    // configure the cell 
} 

per far funzionare tutto correttamente, è inoltre necessario modificare la vostra altro metodo UITableViewDataSource.Invece di:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    return (searchResults) ? (searchResults.count) : (testData.count); 
} 

Do:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    if ([tableView isEqual:self.searchDisplayController.searchResultsTableView]) { 
     return searchResults.count; 
    } 
    return testData.count; 
} 
2

In realtà ci sono due tableViews, UISearchResultsTableView per la visualizzazione del risultato, self.tableView per la visualizzazione dati di origine.

Quando si cerca "Uno" e si cancella tutto il testo di ricerca, è rimasta una sola cella visibile in self.tableView e nessuna cella visibile in UISearchResultsTableView. In realtà in questo momento entrambe le tabelle non dovrebbero avere celle visibili a sinistra. Quindi cerca "T", ora ci dovrebbero essere due celle in UISearchResultsTableView perché "Due" e "Tre" corrispondono a "T", in questo momento c'è solo una cella visibile in self.tableView, il cui testo dell'etichetta è "Uno", dequeueReusableCellWithIdentifier:forIndexPath funziona bene per la riga 0, per la riga 1, si blocca. Penso che la ragione sia che esiste una sola cella visibile per self.tableView.

MyTableViewCell *cell; 
if (tableView != self.tableView) { 
    cell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCell"]; 
} else { 
    cell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCell" forIndexPath:indexPath]; 
} 

E textDidChange, aggiungere questo alla fine di cancellare tableView quando Testo di ricerca è stringa vuota.

if (searchText.length == 0) { 
    [self.tableView reloadData]; 
} 
5

ho scaricato il codice e quello che ho osservato è se cambio il metodo

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 

come segue sta lavorando bene per me.

Soluzione1:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 

    if (tableView == self.searchDisplayController.searchResultsTableView) { 
     return [searchResults count]; 

    } else { 
     return [testData count]; 

    } 

} 

Si prega di farmi sapere se funziona per voi e ciò che il mio suggerimento è quello di utilizzare "NSPredicate" per filtrare la matrice come il seguente.

- (void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { 
    NSLog(@"Search text did change"); 

    NSPredicate *resultPredicate = [NSPredicate 
            predicateWithFormat:@"SELF contains[cd] %@", 
            searchText]; 

    searchResults = [testData filteredArrayUsingPredicate:resultPredicate]; 
} 

Nlote: prendere "searchResults" come NSArray non NSMutableArray.

La soluzione di cui sopra funziona per me Ecco un altro approccio per risolvere il problema.

Solution2:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 

    if (tableView == self.searchDisplayController.searchResultsTableView) { 
     return [searchResults count]; 

    } else { 
     return [testData count]; 

    } 

} 

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope 
{ 
    NSPredicate *resultPredicate = [NSPredicate 
            predicateWithFormat:@"SELF contains[cd] %@", 
            searchText]; 

    searchResults = [testData filteredArrayUsingPredicate:resultPredicate]; 
} 

// I implemented The following delegate method. 


-(BOOL)searchDisplayController:(UISearchDisplayController *)controller 
shouldReloadTableForSearchString:(NSString *)searchString { 

    [self filterContentForSearchText:searchString scope:[[self.searchDisplayController.searchBar scopeButtonTitles] 
    objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]]; 
    return YES; 
} 
+0

@Neil Coffey è la mia risposta ti aiuta. – lazyCoder

+0

Stai ancora affrontando il problema – lazyCoder

2

Dopo aver provato diversi approcci, il mio consiglio è quello di evitare la lotta contro Apple API.

UISearchDisplayController gestisce il proprio UITableView, oltre ad avere la vostra tabella primaria. L'identificativo della cella nella tabella filtrata non corrisponde alla tabella principale.

Come dettagliato qui: UISearchDisplayController and UITableView prototype cell crash


Pertanto, l'approccio migliore è quella che hai già scoperto:

MyCell *cell = (MyCell *) [self.tableView dequeueReusableCellWithIdentifier:@"MyId"]; 

quanto riguarda la questione separatori della tabella "fantasma", che purtroppo Non ero in grado di riprodurlo, vorrei affrontarlo in questo modo:

self.searchDisplayController.searchResultsTableView.separatorColor = [UIColor clearColor]; 

Buona fortuna.

Problemi correlati