5

Aggiornamento 3 Questi sono i registri dopo la prima esecuzione con un archivio dati vuoto.UITableView con NSFetchedResultsController non carica la seconda volta

2013-02-07 20:57:06.708 Five Hundred Things[14763:c07] mainMOC = <NSManagedObjectContext: 0x7475a90> 
2013-02-07 20:57:06.711 Five Hundred Things[14763:1303] Import started 
2013-02-07 20:57:06.712 Five Hundred Things[14763:1303] backgroundMOC = <NSManagedObjectContext: 0x8570070> 
2013-02-07 20:57:06.717 Five Hundred Things[14763:c07] FRC fetch performed 
2013-02-07 20:57:06.718 Five Hundred Things[14763:c07] numberOfSectionsInTableView returns 1 
2013-02-07 20:57:06.720 Five Hundred Things[14763:c07] numberOfSectionsInTableView returns 1 
2013-02-07 20:57:06.720 Five Hundred Things[14763:c07] numberOfRowsInSection returns 0 
2013-02-07 20:57:06.728 Five Hundred Things[14763:1303] call contextDidSave 
2013-02-07 20:57:06.736 Five Hundred Things[14763:1303] call contextDidSave 
2013-02-07 20:57:06.736 Five Hundred Things[14763:c07] numberOfSectionsInTableView returns 1 
2013-02-07 20:57:06.737 Five Hundred Things[14763:c07] numberOfSectionsInTableView returns 1 
2013-02-07 20:57:06.737 Five Hundred Things[14763:c07] numberOfRowsInSection returns 5 
2013-02-07 20:57:06.758 Five Hundred Things[14763:1303] call contextDidSave 
2013-02-07 20:57:06.759 Five Hundred Things[14763:1303] Refresh complete 
2013-02-07 20:57:06.759 Five Hundred Things[14763:c07] numberOfSectionsInTableView returns 1 
2013-02-07 20:57:06.760 Five Hundred Things[14763:c07] numberOfSectionsInTableView returns 1 
2013-02-07 20:57:06.761 Five Hundred Things[14763:c07] numberOfRowsInSection returns 5 

noti che il CRF recuperare viene eseguita, il numero di righe nella sezione è 0, ma poi dopo il secondo contextDidSave, cambia a 5 in base al numero di categorie nell'archivio dati.

Nella seconda corsa con lo schianto, qui i registri:

2013-02-07 21:01:11.578 Five Hundred Things[14800:c07] mainMOC = <NSManagedObjectContext: 0x8225650> 
2013-02-07 21:01:11.581 Five Hundred Things[14800:1303] Import started 
2013-02-07 21:01:11.582 Five Hundred Things[14800:1303] backgroundMOC = <NSManagedObjectContext: 0x7439850> 
2013-02-07 21:01:11.592 Five Hundred Things[14800:c07] FRC fetch performed 
2013-02-07 21:01:11.594 Five Hundred Things[14800:c07] cat = Attraction 
2013-02-07 21:01:11.594 Five Hundred Things[14800:c07] cat = Beverage 
2013-02-07 21:01:11.595 Five Hundred Things[14800:c07] cat = Entertainment 
2013-02-07 21:01:11.595 Five Hundred Things[14800:c07] cat = Hotel 
2013-02-07 21:01:11.596 Five Hundred Things[14800:c07] cat = Restaurant 
2013-02-07 21:01:11.597 Five Hundred Things[14800:c07] numberOfSectionsInTableView returns 1 
2013-02-07 21:01:11.598 Five Hundred Things[14800:c07] numberOfSectionsInTableView returns 1 
2013-02-07 21:01:11.599 Five Hundred Things[14800:c07] numberOfRowsInSection returns 0 
2013-02-07 21:01:11.602 Five Hundred Things[14800:1303] call contextDidSave 
2013-02-07 21:01:11.610 Five Hundred Things[14800:1303] call contextDidSave 

La FRC viene inizializzato, e subito dopo le categorie vengono registrati per dimostrare che sono effettivamente in FRC. Il numero di righe nella sezione, tuttavia, è 0 e non viene mai aggiornato. Invece l'app si blocca con lo stack sottostante.

Sulla terza e le successive esecuzioni, questo è ciò che il registro appare come:

2013-02-07 21:03:55.560 Five Hundred Things[14815:c07] mainMOC = <NSManagedObjectContext: 0x8128860> 
2013-02-07 21:03:55.563 Five Hundred Things[14815:1e03] Import started 
2013-02-07 21:03:55.564 Five Hundred Things[14815:1e03] backgroundMOC = <NSManagedObjectContext: 0x822b5d0> 
2013-02-07 21:03:55.569 Five Hundred Things[14815:c07] FRC fetch performed 
2013-02-07 21:03:55.571 Five Hundred Things[14815:c07] cat = Attraction 
2013-02-07 21:03:55.572 Five Hundred Things[14815:c07] cat = Beverage 
2013-02-07 21:03:55.572 Five Hundred Things[14815:c07] cat = Entertainment 
2013-02-07 21:03:55.573 Five Hundred Things[14815:c07] cat = Hotel 
2013-02-07 21:03:55.573 Five Hundred Things[14815:c07] cat = Restaurant 
2013-02-07 21:03:55.574 Five Hundred Things[14815:c07] numberOfSectionsInTableView returns 1 
2013-02-07 21:03:55.576 Five Hundred Things[14815:c07] numberOfSectionsInTableView returns 1 
2013-02-07 21:03:55.576 Five Hundred Things[14815:c07] numberOfRowsInSection returns 5 
2013-02-07 21:03:55.581 Five Hundred Things[14815:1e03] call contextDidSave 
2013-02-07 21:03:55.592 Five Hundred Things[14815:1e03] call contextDidSave 
2013-02-07 21:03:55.593 Five Hundred Things[14815:c07] numberOfSectionsInTableView returns 1 
2013-02-07 21:03:55.594 Five Hundred Things[14815:c07] numberOfSectionsInTableView returns 1 
2013-02-07 21:03:55.595 Five Hundred Things[14815:c07] numberOfRowsInSection returns 5 
2013-02-07 21:03:55.606 Five Hundred Things[14815:1e03] call contextDidSave 
2013-02-07 21:03:55.606 Five Hundred Things[14815:1e03] Refresh complete 

Questo è come il comportamento dovrebbe apparire sulla seconda corsa; i dati sono già nel negozio, il numero di righe nella sezione restituisce 5 e le categorie vengono visualizzate immediatamente nella vista tabella.


Update 2 Ecco una traccia dello stack del thread principale, che è dove si verifica l'incidente. Dal momento che si sta verificando sul thread principale, penso che abbia qualcosa a che fare con UITableView. Tuttavia, non sto usando NSDictionary o NSMutableDictionary in UITableView. Il mio pensiero ora è che ilrestituendo 0 alla seconda esecuzione sta causando il problema, ma non sono sicuro di come risolverlo. Restituisce il numero corretto (5 con i dati che sto usando) alla terza esecuzione, e sembra popolare l'archivio dati correttamente alla prima esecuzione, quindi sono confuso sul motivo per cui alla seconda esecuzione restituisce 0 e non esegue aggiornamento.

frame #0: 0x013ede52 libobjc.A.dylib`objc_exception_throw 
frame #1: 0x020330de CoreFoundation`-[__NSDictionaryM setObject:forKey:] + 158 
frame #2: 0x01211d7a CoreData`-[NSFetchedResultsController(PrivateMethods) _preprocessUpdatedObjects:insertsInfo:deletesInfo:updatesInfo:sectionsWithDeletes:newSectionNames:treatAsRefreshes:] + 1994 
frame #3: 0x01212ed7 CoreData`-[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:] + 2455 
frame #4: 0x00b9e4f9 Foundation`__57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 + 40 
frame #5: 0x0200a0c5 CoreFoundation`___CFXNotificationPost_block_invoke_0 + 85 
frame #6: 0x01f64efa CoreFoundation`_CFXNotificationPost + 2122 
frame #7: 0x00ad2bb2 Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 98 
frame #8: 0x01125163 CoreData`-[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 83 
frame #9: 0x011bed2f CoreData`-[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:] + 367 
frame #10: 0x01121128 CoreData`-[NSManagedObjectContext(_NSInternalChangeProcessing) _postRefreshedObjectsNotificationAndClearList] + 136 
frame #11: 0x0111f8c0 CoreData`-[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 80 
frame #12: 0x0111f869 CoreData`-[NSManagedObjectContext processPendingChanges] + 41 
frame #13: 0x010f3e38 CoreData`_performRunLoopAction + 280 
frame #14: 0x01f78afe CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30 
frame #15: 0x01f78a3d CoreFoundation`__CFRunLoopDoObservers + 381 
frame #16: 0x01f567c2 CoreFoundation`__CFRunLoopRun + 1106 
frame #17: 0x01f55f44 CoreFoundation`CFRunLoopRunSpecific + 276 
frame #18: 0x01f55e1b CoreFoundation`CFRunLoopRunInMode + 123 
frame #19: 0x01f0a7e3 GraphicsServices`GSEventRunModal + 88 
frame #20: 0x01f0a668 GraphicsServices`GSEventRun + 104 
frame #21: 0x00021ffc UIKit`UIApplicationMain + 1211 
frame #22: 0x000022dd Five Hundred Things`main(argc=1, argv=0xbffff31c) + 141 at main.m:16 
frame #23: 0x00002205 Five Hundred Things`start + 53 

Aggiornamento: Sono riuscito a ottenere un arresto vero e proprio invece di alcuna risposta.

* Chiusura di applicazione a causa di eccezione non identificata 'NSInvalidArgumentException', la ragione: '* setObjectForKey: oggetto non può essere nullo (tasto: _ContentChange_OldIndexPathKey)'

This SO question è il più vicino ho potuto trovare al errore, ma discute il valore essendo nullo invece della chiave. Sembra che si verifichi quando le categorie vengono salvate nell'archivio dei dati principali, ma tutte le categorie hanno valori.

L'entità categoria contiene category_id - Intero 16 category_name - String

Ha un rapporto a-molti con l'entità cosa, ma questa particolare parte del codice non sta facendo nulla per quel rapporto; è solo l'impostazione category_id e category_name. Più tardi nell'importazione (dopo il salvataggio MOC in questione) si verifica quando viene impostata la relazione.

codice in questione dalla operazione di importazione:

//import categories 

    NSString *categoryPath = [[NSBundle mainBundle] pathForResource:@"category" ofType:@"json"]; 

    NSData *categoryData = [NSData dataWithContentsOfFile:categoryPath]; 

    NSDictionary *categoryResults = [NSJSONSerialization 
            JSONObjectWithData:categoryData 
            options:NSJSONReadingMutableLeaves 
            error:&error]; 

    NSEntityDescription *categoryEntity = [NSEntityDescription entityForName:@"Category" 
               inManagedObjectContext:context]; 

    NSMutableArray *categories = [[NSMutableArray alloc] init]; 

    NSString *categoryPredicateString = [NSString stringWithFormat: @"category_id == $CATEGORY_ID"]; 

    NSPredicate *categoryPredicate = [NSPredicate predicateWithFormat:categoryPredicateString]; 


    for (NSDictionary *categoryKey in categoryResults){ 

     NSFetchRequest *categoryFetchRequest = [[NSFetchRequest alloc] init]; 

     [categoryFetchRequest setEntity:categoryEntity]; 

     NSNumber *categoryID = [NSNumber numberWithInt:[[categoryKey objectForKey:@"category_id"] integerValue]]; 

     [categories addObject:categoryID]; 

     NSDictionary *categoryVariables = [NSDictionary dictionaryWithObject:categoryID forKey:@"CATEGORY_ID"]; 

     NSPredicate *catSubPredicate = [categoryPredicate predicateWithSubstitutionVariables:categoryVariables]; 

     [categoryFetchRequest setPredicate:catSubPredicate]; 

     NSArray *categoryArray = [[NSArray alloc] init]; 
     categoryArray = [context executeFetchRequest:categoryFetchRequest error:&error]; 

     Category *categoryObject = [categoryArray lastObject]; 
     NSNumber *categoryNum = [categoryObject valueForKey:@"category_id"]; 
     NSInteger categoryInt = [categoryNum integerValue]; 

     if (categoryInt != [[categoryKey objectForKey:@"category_id"] integerValue]){ 
      categoryObject = [NSEntityDescription 
           insertNewObjectForEntityForName:@"Category" 
           inManagedObjectContext:context]; 
      categoryObject.category_id = [NSNumber numberWithInt:[[categoryKey objectForKey:@"category_id"] intValue]]; 
     } 
     if (categoryObject.category_name != [categoryKey objectForKey:@"category"]){ 
      categoryObject.category_name = [categoryKey objectForKey:@"category"]; 
     } 

    } 

    //Remove unneeded Categories from Core Data Store 

    NSFetchRequest *removeUnusedCategories = [[NSFetchRequest alloc] init]; 
    [removeUnusedCategories setEntity:categoryEntity]; 
    NSArray *fetchedCategories = [context executeFetchRequest:removeUnusedCategories error:&error]; 

    for (Category *fetchedCategory in fetchedCategories){ 
     if (![categories containsObject:fetchedCategory.category_id]){ 
      [context deleteObject:fetchedCategory]; 
      NSLog(@"Object deleted"); 
     } 
    } 

    if (![context save:&error]) { 
     NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]); 
    } 

La [context save] avviene sullo sfondo MOC ed è sincronizzato al principale MOC (nel delegato app) attraverso il centro di notifica. Ascolta NSManagedObjectContextDidSaveNotification ed esegue mergeChangesFromContextDidSaveNotification: sul MOC principale.

La prima corsa e la terza corsa funzionano perfettamente. Si verifica sempre durante la seconda corsa.


sto usando Core Data su un progetto iOS e finora sta funzionando bene tranne che per un problema.

L'applicazione popola il negozio Core Data da file JSON ei carichi UITableViewController iniziale con l'animazione come dovrebbe. Tuttavia, la seconda volta che l'app viene avviata, UITableView iniziale è vuoto. Ho controllato in più punti e i dati si trovano nell'archivio dei dati di base all'avvio del secondo avvio, ma nessuno dei metodi UITableView o NSFetchedResultsController viene chiamato.

Al primo lancio, il numero di righe nella sezione restituisce 0, ma dopo il negozio Nucleo dati vengono caricati i rendimenti 5 come dovrebbe. Al secondo avvio, il numero di righe nella sezione (solo una sezione) restituisce 0 e non si aggiorna. Al terzo e al successivo avvio, il numero di righe nella sezione restituisce 5 come dovrebbe.

Né il cellForRowAtIndexPath di UITableView né i metodi didChangeObject di NSFetchedResultsController vengono richiamati al secondo avvio dell'app. UITableViewController è UITableViewDelegate, UITableViewDataSource e NSFetchedResultsControllerDelegate.

Come suggerito dalle linee guida Core Data, la quota di applicazione delegato e visualizzazione della tabella di controllo di un contesto oggetto gestito mentre il caricamento dei dati è stato fatto su uno sfondo MOC in un altro thread. Questi vengono sincronizzati quando il metodo di salvataggio del contesto viene chiamato tramite mergeChangesFromContextDidSaveNotification:.

Per riprodurre, elimino l'app dal simulatore, eseguo una volta e il database si popola e l'app viene visualizzata correttamente. Fermo l'app e corro di nuovo e non viene visualizzato nulla. Interrompe l'app ed eseguo una terza volta e viene visualizzata correttamente.

Tutto ciò sembra funzionare correttamente tranne che per la seconda volta che si avvia l'app. La prima e la terza volta funzionano correttamente. Cosa mi manca?

Per quanto riguarda il mio codice, non sono sicuro di cosa mettere qui. Iniziamo con l'implementazione di UITableViewController.

@implementation FTWTMasterViewController 

@synthesize managedObjectContext; 
@synthesize categoryController = _categoryController; 
@synthesize catLocViewController; 

- (id)initWithStyle:(UITableViewStyle)style 
{ 
    self = [super initWithStyle:style]; 
    if (self) { 
     // Custom initialization 
    } 
    return self; 
} 

- (NSFetchedResultsController *)categoryController { 
    if (_categoryController != nil) { 
     return _categoryController; 
    } 

    NSLog(@"tableview MOC = %@", self.managedObjectContext); 

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:self.managedObjectContext]; 
    [fetchRequest setEntity:entity]; 

    NSSortDescriptor *sort = [[NSSortDescriptor alloc] 
           initWithKey:@"category_name" ascending:YES]; 
    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]]; 

    [fetchRequest setFetchBatchSize:20]; 

    NSFetchedResultsController *theFetchedResultsController = 
    [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest 
             managedObjectContext:self.managedObjectContext 
              sectionNameKeyPath:nil 
                cacheName:@"CategoryTable"]; 
    _categoryController = theFetchedResultsController; 
    _categoryController.delegate = self; 

    return _categoryController; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    self.tableView.dataSource = self; 
    self.tableView.delegate = self; 

    NSError *error; 
    if (![[self categoryController] performFetch:&error]) { 
     // Update to handle the error appropriately. 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     exit(-1); // Fail 
    } 

    NSLog(@"Fetch called"); 

    self.title = @"Categories"; 
} 

- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated. 
} 

#pragma mark - Table view data source 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    NSLog(@"number of sections = %lu", (unsigned long)[[self.categoryController sections] count]); 
    return [[self.categoryController sections] count]; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    id sectionInfo = 
     [[_categoryController sections] objectAtIndex:section]; 

    NSLog(@"numberOfObjects = %lu", (unsigned long)[sectionInfo numberOfObjects]); 
    return [sectionInfo numberOfObjects]; 
} 

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath { 
    Category *category = [_categoryController objectAtIndexPath:indexPath]; 
    cell.textLabel.text = category.category_name; 
    NSLog(@"config cell %@", category.category_name); 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSLog(@"tableView setup"); 
    static NSString *CellIdentifier = @"categoryCell"; 

    UITableViewCell *cell = 
    [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 

    // Set up the cell... 
    [self configureCell:cell atIndexPath:indexPath]; 

    return cell; 
} 

#pragma mark - Table view delegate 

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    Category *aCategory = [self.categoryController objectAtIndexPath:indexPath]; 

    if (self.catLocViewController == nil){ 
     FTWTCatLocationViewController *aCatLocController = [[FTWTCatLocationViewController alloc] init]; 
     self.catLocViewController = aCatLocController; 
    } 

    self.catLocViewController.selectedCat = aCategory; 
    aCategory = nil; 

    self.catLocViewController.managedObjectContext = self.managedObjectContext; 

    [self.navigationController pushViewController:self.catLocViewController animated:YES]; 

    self.catLocViewController = nil; 
} 

#pragma mark - Fetched results controller delegate 
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { 
    // The fetch controller is about to start sending change notifications, so prepare the table view for updates. 
    [self.tableView beginUpdates]; 
} 

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { 

    NSLog(@"didChangeObject"); 

    UITableView *tableView = self.tableView; 

    switch(type) { 

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

     case NSFetchedResultsChangeDelete: 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

     case NSFetchedResultsChangeUpdate: 
      [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 
      break; 

     case NSFetchedResultsChangeMove: 
      [tableView deleteRowsAtIndexPaths:[NSArray 
               arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      [tableView insertRowsAtIndexPaths:[NSArray 
               arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
    } 
} 


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { 

    switch(type) { 

     case NSFetchedResultsChangeInsert: 
      [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

     case NSFetchedResultsChangeDelete: 
      [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
    } 
} 


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { 
    // The fetch controller has sent all current change notifications, so tell the table view to process all updates. 
    [self.tableView endUpdates]; 
} 

@end 
+0

chiamate mai performFetch: sul controller dei risultati recuperati? e si salva il managedobjectcontext quando si carica la prima volta? – wattson12

+0

'performFetch:' viene chiamato in 'viewDidLoad' (mostrato sopra) e il MOC viene salvato dopo l'importazione di ciascun file JSON. – scottoliver

+0

ViewDidLoad viene chiamato ogni volta che si avvia l'app (in particolare, controllare la seconda volta). Mi sto chiedendo questo perché nel tuo numberOfRowsInSection stai accedendo alla variabile di istanza di ** categoryController ** e non alla proprietà. Quindi questo non chiamerebbe il getter per quello e potrebbe non essere configurato correttamente tramite lazy instantiation. Hai provato a usare self.categoryController in numberOfRows ...? Solo un pensiero iniziale – Firo

risposta

8

Contrariamente a quello che ho assunto nel commento di cui sopra, lo stesso effetto può accadere se un sectionNameKeyPath è specificato per creare vista SEZIONI (ho potuto riprodurre questo con un programma di test).

Quando l'applicazione viene avviata per la prima volta, accade quanto segue: si crea

  1. Un file di archivio permanente "appname.sqlite".
  2. Un controller di risultati recuperato per la vista tabella viene creato con il set di parametri cacheName, in modo che venga creato un file di cache di sezione. A questo punto, tutte le sezioni sono vuote.
  3. Viene creato un MOC in background che legge alcuni dati JSON da un file di risorse e aggiunge oggetti al contesto.
  4. Il MOC di sfondo viene salvato.

(Btw. Il file di cache è

Library/Caches/<bundle-id>/.CoreDataCaches/SectionInfoCaches/<tablename>/sectionInfo 

nel bundle dell'applicazione.)

Quando l'applicazione viene avviata la seconda volta, i recuperati controlla i risultati del controller se la cache informazioni sezione è ancora valido o deve essere ricreato. Secondo la documentazione, confronta i tempi di modifica del file di archivio persistente e il file di cache di sezione.

Ora la parte interessante: se (nella prima manche) la creazione del file di archivio (fase 1) e salvando il contesto aggiornato (fase 4) accada nello stesso secondo, quindi la data di modifica del negozio il file non è stato modificato nel passaggio 4 !!

Pertanto il file della cache di sezione è ancora visto come valido e non ricreato. Poiché tutte le sezioni erano vuote (nel passaggio 2), il FRC utilizza queste informazioni memorizzate nella cache e visualizza solo sezioni vuote.

Il MOC di sfondo viene riavviato e salva il contesto. Ora il file del negozio ha una nuova data di modifica, pertanto le sezioni e le righe vengono visualizzate correttamente nella terza esecuzione dell'app.

Per confermare la mia "teoria", ho fatto un "tocco" manuale del file di archivio tra prima e seconda esecuzione per imporre una data di modifica modificata. Tutte le sezioni e le righe sono state quindi visualizzate correttamente.

(l'ho provato solo su iPhone Simulator .Non so se il file system HFS + generalmente ha una risoluzione di 1 secondo della data di modifica, o se SQLite fa qualcosa di speciale qui. Proverò a indagare più tardi .)

Conclusione: Se la creazione del file di archivio e il salvataggio dei dati modificati accadono nello stesso secondo, un file di cache informazioni sezione non può essere rigenerato, se necessario.

+0

Questo deve essere il caso poiché sto lavorando con un piccolo set di dati in questo momento e l'aggiornamento avviene molto rapidamente. L'altra app che ho menzionato in precedenza utilizza un set di dati molto più ampio in cui la creazione del file del negozio e il salvataggio MOC probabilmente non accadranno mai nello stesso secondo. – scottoliver

+0

rimuovere la cache nel mio caso risolto questo problema .. Ma questo è un bug strano bug. –

+0

Quindi ... Cosa devo fare per caricare correttamente la seconda sezione? Lo stesso problema qui ... –

4

Mi sono imbattuto nello stesso problema. Quando ho caricato i dati, il primo carico andava bene. Quando ho riavviato la mia app, i dati sono scomparsi dalla tabella. Questi erano i miei conteggi:

self.fetchedResultsController.fetchedObjects: 8
[self.fetchedResultsController.sections count]: 1
[self.fetchedResultsController.sections[0] numberOfObjects]: 0

ho la possibilità di cambiare il tipo nell'interfaccia utente e dopo aver cambiato il tipo e poi cambiarlo di nuovo, il problema scomparso, che ha sicuramente indicato un problema di memorizzazione nella cache.

Calling

[NSFetchedResultsController deleteCacheWithName:nil]; 

cancellerà tutte le cache.

Ho anche finito per scegliere di non memorizzare nella cache per ora. Non penso di archiviare decine di migliaia di record nel mio database per queste tabelle, quindi non sono sicuro che la memorizzazione nella cache migliorerà nulla.L'impostazione di cacheName a nil impedirà la memorizzazione nella cache di NSFetchedResultsController.

self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest 
                    managedObjectContext:self.context 
                     sectionNameKeyPath:sectionIdentifier 
                       cacheName:nil]; 
+0

Grazie! che mi ha salvato la giornata È anche una ragione per quel brutto errore. Ma alla fine ho cancellato tutte le mie cache. – Goppinath