8

Ho un UITableView (con celle personalizzate, se questo è importante) collegato a un NSFetchedResultsController. La mia app utilizza anche notifiche push. Quando arriva una notifica remota, aggiorno il mio modello di dati (principale) in due fasi:NSFetchedResultsController ritardo coerente nell'aggiornamento della cella UITableView; inserire funziona immediatamente

1) Ottieni titolo (con alcuni dati personalizzati) e memorizzalo come nuovo core data Entity. Qui chiamo NSManagedObjectContext save(). NSFetchedResultsController preleva l'inserto e attiva il suo metodo delegato didChangeObject con NSFetchedResultsChangeType = NSFetchedResultsChangeInsert. La tableview è immediatamente aggiornata. (È stata inserita una nuova riga)

2) Scaricare più contenuto correlato alla cella tramite NSURLSession inseriscilo nello Entity precedente e chiamare di nuovo lo save() method. NSFetchedResultsController recupera nuovamente l'aggiornamento e attiva il suo metodo delegato didChangeObject con NSFetchedResultsChangeType = NSFetchedResultsChangeUpdate. È qui che chiamo il mio metodo configureCell. Il TableView è aggiornato ma con un ritardo costante di circa 10 secondi.

In entrambe le fasi (download-contesto save-update tableview) i dati che devono essere mostrati sono stati già mantenuti dai dati principali. (Per esempio, all'interno mio metodo configureCell.., io so che non sto impostando qualsiasi etichetta cella per nil o simili

I miei metodi NSFetchedResultsController delegato:.

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { 
[self.mainTableView beginUpdates]; 
} 

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { 
[self.mainTableView endUpdates]; 
} 


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { 
UITableView *tableView = self.mainTableView; 

switch(type) { 

    case NSFetchedResultsChangeInsert: 
     [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     break; 

    case NSFetchedResultsChangeUpdate: 
     [self configureCell:(MessageTableViewCell *)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 
    } 
} 

Altre cose che ho provato dentro case NSFetchedResultsChangeUpdate:

  1. provato a chiamare processPendingChanges prima contesto save
  2. Chiamato reloadRowsAtIndexPaths invece di chiamare configureCell direttamente
  3. provato avvolgendo l'aggiornamento .. metodi all'interno beginUpdates e endUpdates (anche se ho già un paio che dovrebbe fare il lavoro)
  4. [tableView reloadData]
  5. numberOfRowsInSection non è 0!
  6. I metodi delegati NSFetchedResultsController vengono eseguiti solo sul thread principale.

In poche parole, tutti i (?) Metodi di delega appropriati vengono chiamati correttamente. Tuttavia, vedo un ritardo costante di circa 10 secondi durante l'aggiornamento di una cella. Tuttavia, l'inserimento avviene quasi istantaneamente. Qualche idea?

+0

Non viene visualizzato il codice in cui si aggiorna la tabella dopo il completamento dell'operazione di rete, ma suppongo che non si stia inviando l'aggiornamento sulla coda principale. – Paulw11

+0

Beh, se "inviando" l'aggiornamento, intendi chiamare 'save', quindi no, sto chiamando' save' dal metodo delegato 'NSURLSession'' URLSession: downloadTask: didFinishDownloadingToURL: 'che NON è sul thread principale se non erro? –

+0

Quindi stai utilizzando un contesto thread di sfondo che hai creato e salvando le modifiche? – Wain

risposta

4

@ Il commento di Paulw11 su dispatch_async... mi ha spinto nella giusta direzione. Il problema sta nel fatto che ho utilizzato lo stesso oggetto ManagedObjectContext in due thread diversi anche se non lo accedono simultaneamente nello stesso momento. Non appena ho inviato le mie chiamate save (che si trovavano su un thread in background) sulla coda principale (spostandola all'interno di dispatch_async(dispatch_get_main_queue,^{ UIUpdate code here });), i ritardi sono scomparsi. Una possibile spiegazione potrebbe essere che chiamando save su un thread in background risulti che i metodi delegati vengano chiamati sul thread in background.

In ogni caso, tornando alla soluzione, non condividere mai lo stesso oggetto ManagedObjectContext tra più thread. Use parent/child context relationships se si sta aggiornando la data principale in più thread.NSFetchedResultsController funziona anche bene con questo modello.