2013年6月21日 星期五

Core Date - NSFetchedResultsController

最近才看了這個Class, 跟TableView很搭

這裡是我的練習程式, 將之前學的一些東西做了整合(匯入外部DB, DB Migration)
然後對TableView做了一點小變化(原本edit=YES之後, 刪除指示跟移動指示會一起出現, 我拆成兩個按鈕分開顯示, 還有取消滑動出現刪除按鈕)
但本篇著墨在NSFetchedResultsController, TableView相關delegate內容不做解釋

程式內的Move按鈕沒有作用, 雖然會顯示移動指示但不會更改DB排序, 實做有點麻煩, fetchedResult沒有DB排序這動作
可以參考這篇文章, 它做法是在DB新增一個order欄位紀錄排序

這是蘋果的CoreDataBooks範例, 是很好的參考學習來源

RootViewController是個包含TableView子視圖的ViewController, 開始先在viewDidLoad執行
[[self fetchedResultsController] performFetch:&error]
產生NSFetchedResultsController的實體, 並執行DB fetch

接著來看產生NSFetchedResultsController實體的這方法
- (NSFetchedResultsController *)fetchedResultsController
{
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    // Create and configure a fetch request with the Book entity.
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Book" inManagedObjectContext:_managedObjectContext];
    [fetchRequest setEntity:entity];
    
    // Create the sort descriptors array.
    NSSortDescriptor *authorDescriptor = [[NSSortDescriptor alloc] initWithKey:@"writer" ascending:YES];
    NSSortDescriptor *titleDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:authorDescriptor, titleDescriptor, nil];
    [fetchRequest setSortDescriptors:sortDescriptors];
 
    // Create and initialize the fetch results controller.
    _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:_managedObjectContext sectionNameKeyPath:@"writer" cacheName:@"Root"];
    _fetchedResultsController.delegate = self;
    
    // Memory management.
    return _fetchedResultsController;
}
一開始先判斷實體是否存在, 若實體已經產生則return
再來的 fetchRequest設置entity(資料表) 與 SortDescriptor設定排序key
排序這段似乎一定要寫, 不寫在產生NSFetchedResultsController時會出錯
再來就是產生NSFetchedResultsController實體這段
sectionNameKeyPath: 這是問說要不要經由某個Key來產生Section, 不需要的話可以設置nil
cacheName: 抱歉我還沒搞懂...

而NSFetchedResultsControllerDelegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
這幾個就把CoreDataBooks內的幾段複製貼上就好, 當對DB做更動時候之後
會自動呼叫這幾個delegate改變當下tableView顯示方式

而我們要做的就只是跟CoreDate操作DB新增刪除就好, 例如
- (IBAction)addAction:(id)sender {
 Book *book = (Book *)[NSEntityDescription insertNewObjectForEntityForName:@"Book" inManagedObjectContext:_managedObjectContext];
 book.title = @"The Little Match Girl";
 book.writer = @"Anderse";
 book.copyright = [NSDate date];
 [_managedObjectContext save:nil];
}
裡面也只是很簡單地要插入一些資料, 在執行 [_managedObjectContext save:nil]; 之後
因為DB資料有了更動, NSFetchedResultsController會自動幫我們把該顯示的東西顯示出來
不需要自己在手動重新fetchRequest取得Array

同理Delete也是, 看到 commitEditingStyle: 內的UITableViewCellEditingStyleDelete
也只是很簡單地把資料刪除, 儲存, 剩下的事情NSFetchedResultsController會做到好

之後我會在試著練習同時multiple selection然後刪除, 不過這篇到此就好

1 則留言:

  1. | cacheName: 抱歉我還沒搞懂...

    CoreData的最底層還是SQLite
    而 NSFetchedResultsController 是去用一個條件去拿個table中的條件下的資料
    這些的資料則會暫存在 cacheName 這個sql中

    如果把執行過的app, download回mac上面看的話,應該就可以看到這個SQLite File

    FYI:
    http://stackoverflow.com/questions/4295474/iphone-cache-name-for-nsfetchedresultscontroller

    http://developer.apple.com/library/ios/#documentation/CoreData/Reference/NSFetchedResultsController_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40008227-CH1-SW24

    回覆刪除