2011-10-20 92 views
12

我可以在我的應用程序中創建新的託管對象,在一個單獨的視圖中我有一個表視圖,顯示了我擁有的所有對象。刷新NSFetchedResultsController數據?

當我創建一個新的託管對象(在一個完全獨立的視圖中)時,我發出一個通知,試圖讓我的表視圖重新載入包含我剛剛創建的新對象的新數據。

我沒有編輯表格視圖。

只有一個託管上下文。

我不明白我做錯了什麼。如果我關閉了應用程序並重新啓動我的新對象在表格視圖中。我試圖在獲取新對象的通知時調用reloadData,並且我也嘗試再次執行提取操作,但是最後我得到的是一個空表視圖。

在代碼方面,我ListViewController:

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

我viewDidLoad中看起來是這樣的:

- (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]; 
    } 
} 

在我的委託/數據源對象,我有:

@interface MyCommutesTableViewDelegate_DataSource : NSObject 

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

@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext; 

@end 

實現摘錄:

-(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; 
} 

我有機架的UITableView數據源的方法在這裏:

- (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

我恢復了簡單,要求所有的對象,因爲我必須快速解決我的問題,然後我意識到,後我保存了我的上下文,我以前在應用程序啓動時使用的提取請求現在不返回任何數據,也沒有錯誤,但它不會返回任何內容。

所以我想我沒有如何實現NSFetchResultsController的問題。但是,在保存一個新對象後,請求怎麼會開始不返回結果呢?

注意如果我重新啓動,包括新添加的對象,我仍然可以獲得所有對象。

標準要求:

-(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; 
    } 
} 

我在等待一個通知,告訴我已經被添加到核心數據一個新的對象,然後我打電話上面的方法,然後在我的tableview調用reloadData ...

回答

26

您正在將您的UITableViewController設置爲NSFetchedResultsControllerDelegate。那很好。現在嘗試實現在TableViewController的controllerDidChangeContent:方法,像這樣:

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

NSFetchedResultsController會聽在覈心數據刪除或新的對象,並通知其變化的代表(你TableViewController)。檢查Xcode中的Core Data模板項目,通過UITableView中的添加和刪除動畫更好地實現這一點。

+0

當然,你要重新加載_notesTableView在您的案件。 – huesforalice

+10

另外不要忘記'NSFetchedResultsController'只會響應''save:'在'NSManagedObjectContext'上被調用。因此,如果您不保存新創建的實體,則可能看不到此方法。 –

+0

謝謝,我正在實施controllerDidChangeContent:從NSFetchedResultsControllerDelegate協議,調用我tableview上的reloadData。我添加了斷點並調用了此方法,但tableview正在重新加載空。如果我重新啓動應用程序,我可以看到所有記錄,包括新的記錄。我錯過了什麼? PS:我必須實現控制器:didChangeObject:atIndexPath:forChangeType:newIndexPath? – Daniel

2

一定要添加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"]; 
} 

新的管理對象在此之後,表視圖露面。

0

如果有人遇到同樣的問題,就像我剛纔那樣。我已經嘗試了綠色勾號的上述解決方案,但它不適用於我。我跟着Apple's code,一切都很順利。

簡單,只實現了三個「Fetchcontroller」委託功能

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() 
     }