2014-12-03 8 views
5

Ho cercato dappertutto questo errore e ho trovato alcuni post con un comportamento simile ma nessuna soluzione che risolva il problema.Il mix di contenuto UITableViewController statico e dinamico causa NSRangeException

Ho un UITableViewController (dichiarata come statica in SB) che deve Sezioni: Sezione 0 (Ricetta) è statico con 4 celle, sezione 1 (Sapori) dovrebbe essere dinamica

Storyboard Screenshot

Questo è il codice che sto usando per prova:

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    rows = [[NSMutableArray alloc] initWithArray:@[@"test",@"test",@"test",@"test",@"test",@"test",@"test"]]; 
} 


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
// Return the number of sections. 
    return 2; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
// Return the number of rows in the section. 
    switch (section) { 
     case 0: 
     return 4; 
     break; 
     case 1: 
     return rows.count; 
     break; 

     default: 
     break; 
    } 

    return 1; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 

    UITableViewCell *cell; 

    switch (indexPath.section) { 
     case 0: 
     return [super tableView:tableView cellForRowAtIndexPath:indexPath]; 
     break; 

     case 1: 

     cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; 
     if (!cell) 
     { 
// create a cell 
      cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; 
     } 
     cell.textLabel.text = [rows objectAtIndex:indexPath.row]; 
     return cell; 

     default: 
     break; 
    } 

    return cell; 
} 

Ora l'errore che sto ottenendo durante l'esecuzione è: 'NSRangeException', la ragione: '*** - [__ NSArrayI objectAtIndex:]: Indice 1 al di là di limiti [0 .. 0] '

So che mi manca qualcosa di piccolo da qualche parte, qualcuno può aiutarmi?

grazie tanto

+0

un'occhiata a questo http://stackoverflow.com/a/9428324/285190 – Flexicoder

+0

non vedo come il vostro collegamento dovrebbe essere aiutare a questo caso in quanto i problemi descritti non sono uguali ai miei, inoltre sto usando un UITableViewController e non un UIViewController – CRE8IT

+0

si blocca subito dopo numberOfRowsInSection e nemmeno in CellForRowAtIndexPath – CRE8IT

risposta

6

Il problema reale è il modo in cui funzionano i tableViewControllers dinamici e statici.

Se si crea un UITableViewController dinamico, la maggior parte dei metodi restituisce zero o 0 o un altro valore predefinito. Quindi non succede niente di male se non li sovrascrivi nella sottoclasse UITableViewController.

Se si crea un UITableViewController statico, la maggior parte dei metodi "chiede" allo storyboard cosa restituire. In realtà c'è probabilmente qualcosa come un array privato come backing store che contiene tutti i dati necessari. E se non si sovrascrivono i metodi che interrogano questo backing-store, l'implementazione predefinita chiederà all'array gli oggetti negli indici che non esistono.


Il tuo problema è che dici al TableView che ha 2 sezioni e un paio di righe.Quindi tableView chiede al controllore statico UITableViewController su cose come l'altezza della cella nella seconda riga nella seconda sezione. Ma questo indexPath non esiste nel backing store (perché si inserisce una sola riga nella seconda sezione) che viene utilizzata dalla tabella statica.

Quindi è necessario implementare un paio di metodi DataSource e delegare e restituire i propri valori se il TableView vuole accedere a informazioni che non esistono nell'archivio statico.

Se si guarda lo stack di chiamate dell'eccezione, si dovrebbe essere in grado di vedere questi metodi.

Es .:

*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]' 
*** First throw call stack: 
(
    0 CoreFoundation 0x000000010ebaaf35 __exceptionPreprocess + 165 
    1 libobjc.A.dylib 0x000000010e843bb7 objc_exception_throw + 45 
    2 CoreFoundation 0x000000010eaa301e -[__NSArrayI objectAtIndex:] + 190 
    3 UIKit    0x000000010f4dc856 -[UITableViewDataSource tableView:heightForRowAtIndexPath:] + 109 
    4 UIKit    0x000000010f21026b __66-[UISectionRowData refreshWithSection:tableView:tableViewRowData:]_block_invoke + 302 
    5 UIKit    0x000000010f20f8fe -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 4125 
    6 UIKit    0x000000010f214e45 -[UITableViewRowData rectForFooterInSection:heightCanBeGuessed:] + 320 
    7 UIKit    0x000000010f214f3a -[UITableViewRowData heightForTable] + 56 

Al indice 3 dello stack di chiamate si può vedere che -[UITableViewDataSource tableView:heightForRowAtIndexPath:] ha chiamato il codice objectAtIndex: che ha sollevato l'eccezione. Questo è uno dei metodi che trasmettono le loro chiamate al backend store se non si impedisce loro di farlo. Quindi devi implementare questo metodo e restituire qualcosa di utile. E poi continui fino a quando non ci saranno più eccezioni.

Quanti metodi sono necessari potrebbero dipendere dalla configurazione di TableView. Ho implementato i quattro che di solito causano queste eccezioni, in modo da poter vedere il modello si dovrebbe seguire se si vede più eccezioni che sono causati da metodi/delegato UITableViewDataSource non sovrascritti:

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { 
    CGFloat height = 0; 
    if (section == 0) { 
     // static section 
     height = [super tableView:tableView heightForHeaderInSection:section]; 
    } 
    return height; 
} 

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { 
    CGFloat height = 0; 
    if (section == 0) { 
     // static section 
     height = [super tableView:tableView heightForFooterInSection:section]; 
    } 
    return height; 
} 

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 
    CGFloat height = 44; 
    if (indexPath.section == 0) { 
     // static section 
     height = [super tableView:tableView heightForRowAtIndexPath:indexPath]; 
    } 
    return height; 
} 

- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath { 
    NSInteger indentationLevel = 0; 
    if (indexPath.section == 0) { 
     // static section 
     indentationLevel = [super tableView:tableView indentationLevelForRowAtIndexPath:indexPath]; 
    } 
    return indentationLevel; 
} 

e qui è un po ' trucco per rendere i contenuti statici ancora più indipendente dal codice:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    if (section == 0) { 
     // static section 
     return [super tableView:tableView numberOfRowsInSection:section]; 
    } 
    return self.objects.count; 
} 

Se si mescolano le celle dinamiche e statiche, chiamando super diventa molto utile.

+0

oltre a mostrare una soluzione fattibile, ora capisco l'intera complessità del processo grazie alla tua spiegazione ..Lo proverò appena possibile e riferirò – CRE8IT

+0

questa soluzione ha funzionato come un fascino, ho scelto questa risposta per essere il più utile perché spiega anche lo sfondo del processo per quanto riguarda lo stack di eccezione ... grazie mille! – CRE8IT

0

Così sembra che ho trovato il motivo di questo errore. La domanda ora è se ho risolto correttamente o se c'è un altro modo di fare programmaticamente ...

La mia soluzione è: Nell'SB, selezionare la sezione che dovrebbe essere dinamica e fornire il numero di righe massime che conterrà. Per quanto mi riguarda, nel mio caso non voglio che l'utente aggiunga più di 30 sapori a una ricetta, quindi ho fornito 30 righe per questa sezione.

Quando si esegue l'applicazione, la matrice ha solo 7 oggetti, anche se ho impostato le righe da 30 a sezione, rende solo il 7 definita nella matrice e non visualizza l'altra 23.

L' La ragione per cui si verifica l'errore sembra essere che quando vuoi mixare sezioni statiche e dinamiche, devi definire la tabella come statica per poter funzionare. In modalità statica e con SB, sembra che il codice legga il numero di celle che hai in SB per una sezione. Se questo numero è inferiore all'array di dati, sputa una NSRangeException ...

Per ora questa è la mia soluzione poiché so che non avrò più di 30 celle, se qualcuno sa come rimediare a questo problema in un più dinamico, per favore fateci sapere

1

Sembra che questo comportamento non sia banale. Potrebbe essere necessario sovrascrivere tutti i metodi con NSIndexPath. Puoi leggere questo discussion e this one per maggiori informazioni.

+0

Ho perso l'unico thread su Apple, che sembra essere d'aiuto ... Lo proverò appena possibile – CRE8IT

0

Ho sostituito la chiamata a super con UITableViewAutomaticDimension per le altezze di riga e aggiunto il metodo delegate per l'altezza di riga stimata. In iOS 9 ho riscontrato problemi con le righe non espandibili che si espandevano automaticamente in iOS8. Le mie celle statiche erano anche altezze dinamiche e le celle dinamiche sono ad altezza fissa.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath *)indexPath { 
CGFloat height = 44; 
if (indexPath.section == 0) { 
    // static section 
    height = UITableViewAutomaticDimension; 
} 
return height; 

}

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { 
return 44; 

}