2014-11-12 8 views
5

Se chiamo -[UICollectionView performBatchUpdates:] dall'interno viewWillAppear:, all'interno viewDidAppear:, tra questi metodi, o in qualsiasi momento la visione di raccolta non è stato disposto dalla gerarchia maggiore vista UIView, la vista collezione sarà affermare con:UICollectionView performBatchUpdates: si afferma in modo imprevisto se la visualizzazione richiede layout?

*** Terminazione dell'app a causa dell'eccezione non rilevata 'NSInternalInconsistencyException', motivo: 'Aggiornamento non valido: numero di sezioni non valido. Il numero di sezioni contenute nella vista di raccolta dopo l'aggiornamento (X) deve essere uguale al numero delle sezioni contenute nella vista di raccolta prima dell'aggiornamento (X), più o meno il numero di sezioni inserite o eliminate (X inserito, 0 cancellato). '

Dove "X" è il numero di elementi che ho inserito. Ho confermato che l'origine dati è stata aggiornata correttamente e che i percorsi dell'indice nell'aggiornamento sono corretti.

In che modo lo stato della vista raccolta può essere coerente con l'origine dati, quando l'origine dati è stata appena aggiornata immediatamente prima di chiamare performBatchUpdates:? Sembra che qualcosa stia innescando inaspettatamente un reloadData.

risposta

8

UICollectionView sembra avere un comportamento speciale (un bug?): Se ha bisogno di layout, performBatchUpdates: funziona come un reloadData prima di chiamare il blocco di aggiornamento, che esegue il rendering delle modifiche che si intendono apportare durante il blocco di aggiornamento alla raccolta. guarda la contabilità

Se si prevede di avere gli aggiornamenti batch applicate alla vista prima che sia stato correttamente disposto (come da un gestore di notifica in un ambiente in rapida evoluzione del modello di dati, per esempio), è necessario fare in modo che in viewWillAppear: che chiamate layoutIfNeeded sulla vista collezione. Ciò impedirà il recupero della vista di raccolta nella chiamata a performBatchUpdates:.

Abbiamo scoperto questo comportamento mettendo un registro nella nostra vista origine dati di raccolta numberOfSections metodo e stampate questo backtrace per vedere dove è stato chiamato da:

2014-11-12 15:30:06.173 CVCrasher[66830:6387719] [CV] #sections stack: (
0 CVCrasher  0x000000010ba9122d -[MyViewController numberOfSectionsInCollectionView:] + 61 
1 UIKit   0x000000010cfc2811 -[UICollectionViewData _updateItemCounts] + 147 
2 UIKit   0x000000010cfc4a89 -[UICollectionViewData numberOfSections] + 22 
3 UIKit   0x000000010cfaebae -[UICollectionViewFlowLayout _getSizingInfos] + 348 
4 UIKit   0x000000010cfafca9 -[UICollectionViewFlowLayout _fetchItemsInfoForRect:] + 526 
5 UIKit   0x000000010cfab51f -[UICollectionViewFlowLayout prepareLayout] + 257 
6 UIKit   0x000000010cfc2a10 -[UICollectionViewData _prepareToLoadData] + 67 
7 UIKit   0x000000010cfc30e9 -[UICollectionViewData validateLayoutInRect:] + 54 
8 UIKit   0x000000010cf8b7b8 -[UICollectionView layoutSubviews] + 170 
9 UIKit   0x000000010c9d1973 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 521 
10 QuartzCore 0x0000000110cf2de8 -[CALayer layoutSublayers] + 150 
11 QuartzCore 0x0000000110ce7a0e _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380 
12 UIKit   0x000000010c9c5847 -[UIView(Hierarchy) layoutBelowIfNeeded] + 611 
13 UIKit   0x000000010cf9c7b7 -[UICollectionView performBatchUpdates:completion:] + 164 
... 

Qui si può vedere chiaramente che la chiamata a performBatchUpdates: sta colpendo l'origine dati e diventando coerente con il modello modificato prima dello gli aggiornamenti vengono applicati. Quando viene chiamato il blocco stesso, la vista dell'insieme lancia un assert come ho mostrato nella domanda originale.

tl; dr - Quando UICollectionView bisogno di layout, performBatchUpdates: agisce efficacemente come una chiamata alla reloadData e renderà il blocco asserzione aggiornamento batch causa del cattivo contabilità. Chiama layoutIfNeeded in viewWillAppear: per evitare questo comportamento.

+0

Significa richiamare 'layoutIfNeeded' in' viewWillAppear: 'e chiamare' performBatchUpdates: 'successivamente in' viewDidAppear: '? Quindi quando chiamate 'performBatchUpdates:' in 'viewDidAppear:', UICollectionView controllerà di trovarlo senza bisogno di fare di nuovo il layout e non chiamerà 'reloadData'? –

+3

Questo bizzarro errore ha richiesto più di un giorno per risolverlo. Grazie per la tua risposta, mi ha indirizzato nella giusta direzione. Fare 'layoutIfNeeded' in' viewWillAppear' non funziona per noi perché gli aggiornamenti iniziano anche prima - ma facendo un 'layoutIfNeeded' proprio prima che il nostro modello di dati lo aggiorni! Questo dovrebbe essere sicuramente classificato come un bug per Apple.Se decidono di eseguire 'reloadData' invece degli aggiornamenti batch, devono eliminare il blocco di aggiornamento batch per evitare incongruenze. – Accatyyc

Problemi correlati