2009-12-10 14 views
5

Ho alcune regole piuttosto complicate per lo spostamento di righe in un UITableView. Esistono un numero indefinito di sezioni e righe per sezione e, in base a varie regole, le righe possono essere spostate all'interno o tra sezioni dell'utente in posizioni specifiche.Blocco durante il tentativo di spostare righe UITableView

Tutti i dati di aggiornamento e tutto funziona. Ma occasionalmente, dopo aver spostato una riga, l'app si spegnerà e improvvisamente ci sarà uno spazio vuoto dove dovrebbe essere visualizzata una riga.

sto usando:

   - (NSIndexPath *)tableView:(UITableView *)tableView 
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath 

per specificare in cui l'utente è autorizzato a trascinare i file in base a dove la cella è. Il 98% delle volte funziona. Ma in alcuni casi, quando l'utente può trascinare solo le sezioni (impossibile riordinare le righe all'interno della sezione), viene visualizzato questo errore, quindi l'app si arresta in modo anomalo dopo aver fatto scorrere l'area senza righe.

L'eccezione generata è abbastanza inutile:

terminazione app a causa di eccezione non identificata 'NSRangeException', la ragione: '*** - [NSCFArray objectAtIndex:]: indice (6) al di là di confini (6)

Nessuno del mio codice è in pila. L'ultimo metodo UITableView-specifico è

-[UITableView(UITableViewInternal) _visibleCellForGlobalRow:]

Qualcuno ha visto questo problema si verifica prima? Qualche idea?

+0

Hai mai risolvere questo Ed? Non c'è una risposta contrassegnata corretta e sto vedendo gli stessi problemi. – coneybeare

+0

No, non ho mai risolto questo problema. Ho dovuto allentare le regole che governano il punto in cui è possibile trascinare una riga in modo che non avvenga –

+0

Stai facendo qualsiasi tipo di operazione di ricarica (come reloadData, reloadSections o reloadRowsAtIndexPath) nel tuo metodo moveRowAtIndexPath? Stavo avendo lo stesso tipo di problema, e ho provato a fare una ricarica in un performSelector ritardato come suggerito da Tom S. in basso, e sembrava funzionare, tranne che ho messo il ritardo a 1 secondo per mantenere iPhone 3.x, 4 .x, e il simulatore felice. È un po 'hacker essere sicuro. –

risposta

0

Non ho visitato questo problema da un po '. La soluzione che ho trovato è stata la rimozione delle regole complicate. Non sono sicuro del motivo per cui hanno permesso l'utilizzo di regole complicate se si è verificato un crash dell'applicazione durante l'utilizzo. Non sono sicuro se questo è stato risolto nell'ultima versione del sistema operativo o meno.

1

Sembra che qualcosa da qualche parte stia richiedendo l'elemento 6 da una matrice che ha solo elementi negli indici 0-5 (ovvero 6 elementi).

Questo di solito accade quando il codice cerca di fare:

NSUInteger index = [somearray count]; 
id obj = [somearray objectAtIndex:index]; 

perché count è limite superiore e gli array partono da 0 l'ultimo elemento è a count - 1.

Questo potrebbe non essere direttamente nel codice ma è possibile limitare un elemento a un numero di elementi e quindi richiedere l'ultimo elemento.

+0

Si noti che si dovrebbe usare 'NSUInteger' per il risultato di' count', per evitare che venga troncato (in particolare quando si sposta il codice sul Mac, dove 'NSUInteger' è, sempre più spesso, più grande di un' int'). È anche importante mantenerlo non firmato in modo che i confronti con questo valore mai negativo abbiano sempre un senso. –

+0

Vero, ero solo pigro ... – stefanB

+0

Sono a conoscenza del problema di base, ma il codice che accede all'array è in profondità all'interno del framework. Come ho detto, al momento dello schianto non c'è assolutamente alcun codice personale in pila. Alla sua base, sembra un bug nell'oggetto UITableView. –

1

Ho avuto un errore simile con la cancellazione che non riuscivo a capire per un po '- ma ho messo [tableView beginUpdates] e [tableView endUpdates] intorno al codice e ha risolto tutto. Potrebbe essere che l'origine dati non si aggiorni prima che tenti di ridisegnare, e quei metodi dovrebbero impedirlo (vale la pena, comunque).

+0

Già fatto, in realtà. –

1

State aggiornamento del modello di dati per la tabella in targetIndexPathForMoveFromRowAtIndexPath

O nel metodo DataSource delegato: tableView:moveRowAtIndexPath:toIndexPath:?

Tratto da tabella visualizza guida di programmazione per iPhone OS, sotto le celle della tabella di riordino:

La vista tabella e che sono inviati tableView: moveRowAtIndexPath: toIndexPath: alla sua fonte di dati (se implementa la metodo).In questo metodo, l'origine dati aggiorna l'array modello dati che è l'origine degli articoli per la vista tabella , spostando l'elemento in una posizione nell'array.

E per il metodo delegato, è scritto:

Ogni volta che la riga trascinato è finita una destinazione , la visualizzazione della tabella invia tableView: targetIndexPathForMoveFromRowAtIndexPath: toProposedIndexPath: al suo delegato (se implementa il metodo ). Con questo metodo il delegato può rifiutare la destinazione corrente per la riga trascinata e specificare uno alternativo .

tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath: è per determinare se un trasferimento è consentito, ma i cambiamenti effettivi al vostro modello di dati dovrebbe avvenire in tableView:moveRowAtIndexPath:toIndexPath:

Forse questo è quello che stai facendo, ma non posso dire solo dalla informazioni fornite.

+0

No, lo sto aggiornando nel metodo moveRowAtIndexPath –

2

Ho appena colpito quello che credo sia lo stesso problema nella mia app.

La situazione è che ho due sezioni di tabella. Gli oggetti possono essere trascinati all'interno e tra le sezioni. Gli utenti possono trascinare le celle su qualsiasi riga nella prima sezione, ma nella seconda sezione gli elementi sono ordinati, quindi per ogni cella, c'è solo una riga valida.

Se si scorre la vista in modo che la parte inferiore della sezione 1 e la parte superiore della sezione 2 siano visibili, afferrare un elemento nella sezione 1 che ordina la parte inferiore della sezione 2 e trascinarlo nella parte superiore della sezione 2 , il mio metodo tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath: viene chiamato e restituisco la posizione di destinazione corretta, che è diverse righe sotto la parte inferiore dello schermo. Nell'interfaccia utente, è possibile vedere una cella vuota viene creata nella parte inferiore dello schermo, che non è la riga di destinazione corretta.

Quando lasci andare la cella, quella cella fasulla che è stata creata nella parte inferiore dello schermo (nel mezzo della sezione 2) rimane lì! tableView:cellForRowAtIndexPath: non viene mai nemmeno chiamato per questo. Non appena provi a fare qualcosa con quella cella, ti blocchi.

La mia prima soluzione era chiamare semplicemente [tableView reloadData] alla fine di tableView:moveRowAtIndexPath:toIndexPath:. Ma questo causa un crash, quindi invece lo chiamo indirettamente dopo un ritardo. Ma poi c'è il un altro bug: dopo la chiamata di reloadData in ritardo, tableView:moveRowAtIndexPath:toIndexPath: viene richiamato nuovamente con una richiesta fasulla di spostare un oggetto oltre la fine della prima sezione nella stessa posizione. Quindi, ho dovuto aggiungere del codice per ignorare le richieste non opzionali false.

Quindi, ecco il codice:

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)pathSrc toIndexPath:(NSIndexPath *)pathDst 
{ 
    // APPLE_BUG: after doing the delayed table reload (see below), we get a bogus 
    // request to move a nonexistant cell to its current location 
    if (pathSrc.row == pathDst.row && pathSrc.section == pathDst.section) 
    return; 

    // update your data model to reflect the move... 

    // APPLE_BUG: if you move a cell to a row that's off-screen (because the destination 
    // has been modified), the bogus cell gets created and eventually will cause a crash 
    [self performSelector:@selector(delayedReloadData:) withObject:tableView afterDelay:0]; 
} 

- (void)delayedReloadData:(UITableView *)tableView 
{ 
    Assert(tableView == self.tableView); 
    [tableView reloadData]; 
} 

Nota che c'è ancora un bug dell'interfaccia utente. Sullo schermo, la cella trascinata viene animata nella cella vuota fasulla. Alla fine dell'animazione, la cella vuota viene ridisegnata con i dati corretti per quella riga, ma l'utente osservante noterà che la cella trascinata si è animata nel punto sbagliato e quindi si è immediatamente trasformata in un'altra cella.

Questa è sicuramente una stupida interfaccia utente.Ho preso in considerazione lo scorrimento della riga di destinazione corretta sullo schermo, ma se dovessi farlo riempirebbe lo schermo con la sezione due e quindi qualsiasi tentativo di tornare alla sezione uno sarebbe continuamente ostacolato dal mio (ora fastidioso) autoscorrimento. Potrei dover cambiare l'interfaccia utente, ma ciò richiederebbe alcune modifiche complesse e fastidiose al mio modello di dati.

+0

Sono contento che almeno un'altra persona abbia avuto la mia stessa esperienza! –

0

Mi è capitato di assistere a questo problema. Tuttavia, la mia versione di crash sembra verificarsi su un dispositivo iOS 3.0 che sto cercando di supportare, e ho solo due righe nella tabella che sto cercando di riorganizzare. Ho eseguito nuovamente l'app con lo stesso codice su un altro dispositivo con iOS 4.0 e il bug sembra essere stato corretto.

Sto ancora ricercando questo, ma a partire da ora, sto disabilitando lo spostamento di righe su dispositivi con iOS 3.0 fino a quando non viene trovata una soluzione.

1

Qui dell'incotroArray è un array ...

id obj =[Cityarray objectatindex:sourceindexpath.row]; 
     [Cityarray removeObjectatindex:(sourceindexpath.row)]; 
     [Cityarray insertObject:obj atindex:destinationindexpath.row]; 
Problemi correlati