2011-10-20 24 views
12

Mogę tworzyć nowe zarządzane obiekty wewnątrz mojej aplikacji, w osobnym widoku Mam widok tabeli, który pokazuje wszystkie posiadane obiekty.Odśwież dane NSFetchedResultsController?

Kiedy tworzę nowy zarządzany obiekt (w całkowicie osobnym widoku), wysyłam powiadomienie, które próbuje uzyskać mój widok tabeli do ponownego załadowania z nowymi danymi, które obejmują właśnie nowo utworzony obiekt.

Nie edytuję widoku tabeli.

Jest tylko jeden zarządzany kontekst.

Nie mogę pojąć, co robię źle. Jeśli zamknę aplikację i uruchomię ponownie, mój nowy obiekt znajduje się w widoku tabeli. Próbuję wywołać reloadData, gdy otrzymam powiadomienie, że nowy obiekt został utworzony, a także próbowałem ponownie wykonać pobieranie, ale wszystko, co mam, to pusty widok tabeli.

Pod względem kodu, mój ListViewController:

@interface MyNotesViewController : UIViewController 
{ 
    NSManagedObjectContext * __managedObjectContext; 
    UITableView * _notesTableView; 
    MyNotesTableViewDelegate_DataSource * _tableDelegate_DataSource; 
} 

My viewDidLoad wygląda następująco:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    _tableDelegate_DataSource = [[MyNotesTableViewDelegate_DataSource alloc] init]; 
    _tableDelegate_DataSource.managedObjectContext = __managedObjectContext; 
    [_notesTableView setDataSource:_tableDelegate_DataSource]; 

    NSError * _coreDataError; 
    BOOL success = [[_tableDelegate_DataSource fetchedResultsController] performFetch:&_coreDataError]; 

    if(success){ 
     [_notesTableView reloadData]; 
    } 
} 

W moim delegata/obiektu źródła danych mam: fragment

@interface MyCommutesTableViewDelegate_DataSource : NSObject 

<UITableViewDataSource, NSFetchedResultsControllerDelegate> 
{ 
    NSManagedObjectContext * __managedObjectContext; 
    NSFetchedResultsController * __fetchedResultsController; 
} 

@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext; 

@end 

implementacji :

-(NSFetchedResultsController*)fetchedResultsController{ 
    if(!__fetchedResultsController){ 
     NSFetchRequest * request = [[NSFetchRequest alloc] init]; 
     [request setEntity:[NSEntityDescription entityForName:@"Note" inManagedObjectContext:__managedObjectContext]]; 

     [request setFetchBatchSize:10]; 

     NSSortDescriptor * sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"noteDate" ascending:NO]; 
     [request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]]; 
     [sortDescriptor release]; 

     __fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:__managedObjectContext sectionNameKeyPath:nil cacheName:nil]; 


     __fetchedResultsController.delegate = self; 
     [request release]; 

    } 
    return __fetchedResultsController; 
} 

Mam metody Stander źródłowe danych UITableView tutaj:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
    return 1; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 
    id <NSFetchedResultsSectionInfo> sectionInfo = 
    [[__fetchedResultsController sections] objectAtIndex:section]; 
    return [sectionInfo numberOfObjects]; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 

    static NSString *CellIdentifier = @"NotesTableViewCell"; 

    NotesTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) {   
     NSArray * topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"NotesTableViewCell" owner:nil options:nil]; 
     for(id currentObject in topLevelObjects){ 
      if([currentObject isKindOfClass:[UITableViewCell class]]){ 
       cell = (NotesTableViewCell*) currentObject; 
       break; 
      } 
     } 

    } 

// Configure the cell. 
    Note * _note = [__fetchedResultsController objectAtIndexPath:indexPath]; 

    [...] 

    return cell; 
} 

UPDATE

I powrócił po prostu zainteresowanie wszystkich obiektów, bo musiałem szybko rozwiązać mój problem, i wtedy zdałem sobie sprawę, po Zapisuję kontekst, moja prośba o pobieranie, której wcześniej używałam przy uruchamianiu aplikacji, teraz nie zwraca żadnych danych, nie ma błędu, ale nic nie zwraca.

Sądzę więc, że nie ma problemu z implementacją NSFetchResultsController. Ale w jaki sposób żądanie mogło zacząć nie zwracać wyników po zapisaniu nowego obiektu?

Uwaga: nadal otrzymuję wszystkie moje obiekty, jeśli uruchomię ponownie, w tym nowo dodany.

standardowy wniosek:

-(NSArray*)getNotes{ 
    NSFetchRequest * request = [[NSFetchRequest alloc] init]; 

    NSEntityDescription * entity = [NSEntityDescription entityForName:@"Note" inManagedObjectContext:[self managedObjectContext]]; 
    [request setEntity:entity]; 

    NSSortDescriptor * sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"noteDate" ascending:NO]; 
    [request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]]; 
    [sortDescriptor release]; 

    NSError * coreDataError; 
    NSArray * fetchedObjects = [[self managedObjectContext] executeFetchRequest:request error:&coreDataError]; 
    [request release]; 

    if(fetchedObjects != nil){ 
     return fetchedObjects; 
    } else { 
     NSLog(@"ERR: %@", coreDataError); 
     return nil; 
    } 
} 

czekam na zgłoszenia mówi mi nowy obiekt został dodany do danych Core, a następnie Wołam powyższej metody, a następnie wywołanie reloadData na moim tableview ...

Odpowiedz

26

Ustawiasz swój UITableViewController jako NSFetchedResultsControllerDelegate. Dobre. Teraz starają się wdrożyć metodę w TableViewController controllerDidChangeContent: tak:

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

Twój NSFetchedResultsController wysłucha usunięte lub nowych obiektów w danych Core i powiadomić swojego delegata (Twój TableViewController) zmian. Sprawdź projekt szablonu danych podstawowych w Xcode, aby jeszcze lepiej zaimplementować animacje dodawania i usuwania w UITableView.

+0

oczywiście będziesz chciał przeładować _notesTableView w Twoim przypadku. – huesforalice

+10

Nie zapominaj również, że 'NSFetchedResultsController' zareaguje tylko na' -save: 'wywoływane w' NSManagedObjectContext'. Tak więc możesz nie zobaczyć tej metody, jeśli nie zapisujesz nowo utworzonego obiektu. –

+0

Dzięki, wdrażam controllerDidChangeContent: z protokołu NSFetchedResultsControllerDelegate, wywołując reloadData na moim tableview. Dodałem punkty przerwania i ta metoda jest wywoływana, ale widok tabeli jest przeładowywany pusty. Jeśli ponownie uruchomię aplikację, zobaczę wszystkie moje rekordy, w tym nową. czego mi brakuje? PS: czy muszę zaimplementować kontroler: didChangeObject: atIndexPath: forChangeType: newIndexPath? – Daniel

2

Pamiętaj, aby dodać metodę didChangeObject:

- (void)controller:(NSFetchedResultsController *)controller 
    didChangeObject:(id) anObject 
     atIndexPath:(NSIndexPath *)indexPath 
    forChangeType:(NSFetchedResultsChangeType)type 
     newIndexPath:(NSIndexPath *)newIndexPath 
{ 
    switch(type) 
    { 
    case NSFetchedResultsChangeInsert: 
     [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 
          withRowAnimation:UITableViewRowAnimationFade]; 
     break; 
    case NSFetchedResultsChangeDelete: 
     [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
          withRowAnimation:UITableViewRowAnimationFade]; 
     break; 
    case NSFetchedResultsChangeUpdate: 
     [self configureCell:[self.tableView 
    cellForRowAtIndexPath:indexPath] 
       atIndexPath:indexPath]; 
     break; 
    case NSFetchedResultsChangeMove: 
     [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
          withRowAnimation:UITableViewRowAnimationFade]; 
     [self.tableView insertRowsAtIndexPaths:[NSArray 
          arrayWithObject:newIndexPath] 
          withRowAnimation:UITableViewRowAnimationFade]; 
     break; 
    } 
} 

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath 
{ 
    NSManagedObject *note = [self.fetchedResultsController objectAtIndexPath:indexPath]; 
    cell.textLabel.text = [note valueForKey:@"title"]; 
} 

Nowy udało obiekt pojawił się w widoku tabeli po tym.

0

Jeśli ktoś ma ten sam problem, co właśnie miałem. Próbowałem powyższego rozwiązania z zielonym kleszczem, ale nie zadziałałoby to dla mnie. Śledziłem Apple's code i wszystko poszło dobrze.

po prostu, po prostu realizować trzy „Fetchcontroller” funkcje delegata

func controllerWillChangeContent(controller: NSFetchedResultsController) { 
      self.tableView.beginUpdates() 
     } 


    func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { 

      switch type { 
      case .Insert: 
       self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade) 
      case .Delete: 
       self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade) 
      case .Update: 
       print("") 
       self.configureCell(self.tableView.cellForRowAtIndexPath(indexPath!)!, indexPath: indexPath!) 
      case .Move: 
       self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade) 
       self.tableView.insertRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade) 
      } 
     } 


func controllerDidChangeContent(controller: NSFetchedResultsController) { 
      self.tableView.endUpdates() 
     } 
Powiązane problemy