5

Aktualizacja 3 Są to dzienniki po pierwszym uruchomieniu z pustym magazynem danych.UITableView z NSFetchedResultsController nie ładuje się po raz drugi

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 

Zauważ, że FRC sprowadzić jest wykonywana, liczba wierszy w sekcji wynosi 0, ale potem po drugim contextDidSave, zmienia się 5 dopasować liczbę kategorii w magazynie danych.

Na drugim biegu z katastrofy, oto logi:

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 

FRC jest inicjowany, a zaraz potem te kategorie są rejestrowane, aby pokazać, że są one rzeczywiście w FRC. Liczba wierszy w tej sekcji wynosi 0 i nigdy nie jest aktualizowana. Zamiast tego aplikacja rozbija się o stos poniżej.

na stokach trzecim i następnych, to co dziennik wygląda następująco:

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 

ten sposób zachowanie powinno wyglądać na drugim biegu; dane są już w sklepie, liczba wierszy w sekcji zwraca 5, a kategorie pojawiają się natychmiast w widoku tabeli.


Aktualizacja 2 Oto ślad stosu głównego wątku, czyli tam, gdzie występuje awaria. Ponieważ dzieje się to w głównym wątku, myślę, że ma to coś wspólnego z UITableView. Nie korzystam jednak z NSDictionary lub NSMutableDictionary w UITableView. Moja myśl teraz jest, że numberOfRowsInSection zwracanie 0 w drugim uruchomieniu jest przyczyną problemu, ale nie jestem pewien, jak rozwiązać ten problem. Zwraca poprawną liczbę (5 z danymi, których używam) w trzecim uruchomieniu i wydaje się zapełnić poprawnie magazyn danych w pierwszym uruchomieniu, więc nie jestem pewien, dlaczego w drugim uruchomieniu zwraca 0 i robi aktualizacja.

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 

Aktualizacja: udało mi się dostać rzeczywistej awarii zamiast po prostu nie ma odpowiedzi.

* Zakończenie aplikację spowodowane nieprzechwyconego wyjątku 'NSInvalidArgumentException', powód: '* setObjectForKey: obiekt nie może być zerowa (klucza: _ContentChange_OldIndexPathKey)'

This SO question jest najbliżej mogę znaleźć do błąd, ale omawia wartość zero zamiast klucza. Wygląda na to, że występuje, gdy kategorie są zapisywane w magazynie danych podstawowych, ale wszystkie kategorie mają wartości.

Podmiot Kategoria zawiera category_id - Integer 16 CATEGORY_NAME - String

Ma relacji do wielu z podmiotem rzecz, ale ta konkretna część kodu nie robi nic dla tej relacji; ustawia tylko identyfikator category_id i category_name. Później w imporcie (po zapisaniu MOC w pytaniu) jest, gdy relacja jest ustawiona.

kod w pytaniu z operacji importu:

//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]); 
    } 

[context save] występuje na tle MOC i jest zsynchronizowany z głównym MOC (w app delegata) przez centrum powiadomień. Słucha dla NSManagedObjectContextDidSaveNotification i uruchamia mergeChangesFromContextDidSaveNotification: na głównym MOC.

Pierwszy bieg i trzeci bieg działają idealnie. Zawsze występuje po drugim uruchomieniu.


Używam danych podstawowych w projekcie iOS i jak na razie działa on dobrze, z wyjątkiem jednego problemu.

Aplikacja zapełnia zawartość magazynu danych podstawowych z plików JSON, a początkowy obiekt UITableViewController ładuje z animacją tak, jak powinien. Jednak przy drugim uruchomieniu aplikacji początkowy UITableView jest pusty. Sprawdziłem w wielu miejscach i dane są w magazynie danych podstawowych, gdy rozpoczyna się drugie uruchomienie, ale nie są wywoływane żadne metody UITableView lub NSFetchedResultsController.

Przy pierwszym uruchomieniu liczba wierszy w sekcji zwraca 0, ale po załadowaniu magazynu danych podstawowych zwraca 5 tak, jak powinna. Przy drugim uruchomieniu liczba wierszy w sekcji (tylko jedna sekcja) zwraca 0 i nie aktualizuje się. Po trzecim i kolejnym uruchomieniu liczba wierszy w sekcji zwraca 5, tak jak powinna.

Podczas wywoływania aplikacji nie są wywoływane metody cellForRowAtIndexPath UITableView ani metody NSFetchedResultsController. Sterownik UITableViewController to UITableViewDelegate, UITableViewDataSource i NSFetchedResultsControllerDelegate.

Zgodnie z sugestiami zawartymi w wytycznych dotyczących danych podstawowych, delegat aplikacji i kontroler widoku tabeli udostępniają kontekst obiektu zarządzanego, podczas gdy ładowanie danych odbywa się na MOC w tle w innym wątku. Są one synchronizowane, gdy metoda zapisu kontekstu jest wywoływana przez mergeChangesFromContextDidSaveNotification:.

Aby odtworzyć, usuwam aplikację z symulatora, uruchamiam raz i zapełnia się baza danych, a aplikacja wyświetla się poprawnie. Zatrzymuję aplikację i znowu biegam i nic nie wyświetla. Zatrzymuję aplikację i uruchamiam po raz trzeci i wyświetla się poprawnie.

Wszystko to wydaje się działać poprawnie, z wyjątkiem drugiego uruchomienia aplikacji. Pierwszy i trzeci czas działają poprawnie. czego mi brakuje?

Co do mojego kodu, nie jestem pewien, co tu umieścić. Zacznijmy od implementacji 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

czy kiedykolwiek wywołasz performFetch: na kontrolerze pobranych wyników? i czy zapisujesz managedobjectcontext podczas ładowania za pierwszym razem? – wattson12

+0

'performFetch:' jest wywoływane w 'viewDidLoad' (pokazanym powyżej), a MOC jest zapisywany po zaimportowaniu każdego pliku JSON. – scottoliver

+0

Czy viewDidLoad jest wywoływana za każdym razem, gdy uruchamiasz aplikację (szczególnie po raz drugi). Zastanawiam się, ponieważ w twojej numberOfRowsInSection uzyskujesz dostęp do ** instancji categoryController **, a nie do właściwości. Więc nie nazwałoby to gettera i nie mogło poprawnie ustawić go za pomocą leniwego tworzenia. Czy próbowałeś używać self.categoryController w numberOfRows ...? Tylko pierwsza myśl. – Firo

Odpowiedz

8

Wbrew Przypuszczałem w powyższym komentarzu, ten sam efekt może się zdarzyć, jeśli sectionNameKeyPath jest określona, ​​aby utworzyć widok tabeli sekcje (mogę odtworzyć ten z program testowy).

gdy aplikacja jest uruchomiona po raz pierwszy, dodaje się dzieje:

  1. Trwały plik magazynu „appname.sqlite” jest tworzony.
  2. Kontroler pobranych wyników dla widoku tabeli jest tworzony za pomocą zestawu parametrów cacheName, dzięki czemu tworzony jest plik pamięci podręcznej sekcji. W tym momencie wszystkie sekcje są puste.
  3. Utworzono MOC w tle, który odczytuje niektóre dane JSON z pliku zasobów i dodaje obiekty do kontekstu.
  4. MOC zostanie zapisany w tle.

(Btw. Plik cache jest

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

w pakiecie aplikacji.)

gdy aplikacja jest uruchomiona po raz drugi, pobranego sterownik sprawdza wyniki czy informacji sekcja cache jest nadal ważne lub musi zostać odtworzone. Zgodnie z dokumentacją porównuje czasy modyfikacji pliku magazynu trwałego i pliku pamięci podręcznej sekcji.

Teraz interesująca część: Jeśli (w pierwszym uruchomieniu) tworzenie pliku przechowywania (krok 1) i zapisywanie zaktualizowanego kontekstu (krok 4) odbywa się w tej samej drugiej, to data modyfikacji sklepu plik nie został zmieniony w kroku 4 !!

W związku z tym plik pamięci podręcznej sekcji nadal jest uznawany za poprawny, a nie został odtworzony. Ponieważ wszystkie sekcje były puste (w kroku 2), FRC używa tej buforowanej informacji i wyświetla tylko puste sekcje.

Tło MOC jest ponownie uruchamiany i zapisuje kontekst. Teraz plik magazynu ma nową datę modyfikacji, dlatego sekcje i wiersze są poprawnie wyświetlane w trzecim uruchomieniu aplikacji.

Aby potwierdzić moją "teorię", wykonałem ręczny "dotyk" pliku magazynu między pierwszym a drugim uruchomieniem, aby wymusić zmianę daty modyfikacji. Wszystkie sekcje i wiersze zostały następnie wyświetlone poprawnie.

(Testowałem to tylko w Symulatorze iPhone'a Nie wiem, czy system plików HFS + ma na ogół 1 sekundę rozdzielczości daty modyfikacji, czy też SQLite robi tu coś specjalnego. Postaram się zbadać to później. .)

Wniosek: Jeśli tworzenie pliku magazynu i zapisywanie zmodyfikowanych danych odbywa się w tej samej sekundzie, plik pamięci podręcznej sekcji może nie zostać w razie potrzeby zregenerowany.

+0

To musi mieć miejsce, ponieważ pracuję teraz z małym zestawem danych i aktualizacja przebiega bardzo szybko. Inna aplikacja, o której wspomniałem wcześniej, używa znacznie większego zestawu danych, w którym tworzenie pliku sklepu i zapisywanie MOC prawdopodobnie nigdy nie miałyby miejsca w tej samej sekundzie. – scottoliver

+0

usunięcie pamięci podręcznej w moim przypadku rozwiązało ten problem .. Ale to jest trochę dziwny błąd. –

+0

Więc ... Co należy zrobić, aby prawidłowo załadować drugą sekcję? Ten sam problem tutaj ... –

4

Wpadłem na ten sam problem. Kiedy ładowałem dane, pierwsze ładowanie było w porządku. Po ponownym uruchomieniu aplikacji dane zniknęły z tabeli. Były to moje liczy:

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

mam możliwość zmiany sortowania w interfejsie użytkownika i po zmianie rodzaju, a następnie zmieniając go z powrotem znowu, problem zniknął, co zdecydowanie wskazywało na problem z buforowaniem.

Wywołanie

[NSFetchedResultsController deleteCacheWithName:nil]; 

usunie wszystkie bufory.

Skończyło się na tym, że zdecydowałem się nie przechowywać pamięci podręcznej na teraz. Nie sądzę, że będę przechowywać dziesiątki tysięcy rekordów w mojej bazie danych dla tych tabel, więc nie jestem pewien, czy buforowanie poprawi cokolwiek.Ustawienie cacheName na nil uniemożliwi buforowanie dla NSFetchedResultsController.

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

Dzięki! to uratowało mój dzień. To także powód tego paskudnego błędu. Ale w końcu usunąłem wszystkie moje pamięci podręczne. – Goppinath

Powiązane problemy