CoreData学习笔记(二)

原创 2011年10月13日 20:56:42

这篇文章重点讲讲CoreData的Fetched Results Controller。

             对应的objc类为NSFetchedResultsController。这个类是用来管理CoreData Fetch request返回的对象的。

             在创建这个控制器之前,必须先创建fetch request。 fetch request描述了详细的查询规则,还可以添加查询结果的排序描述(sort descriptor)。fetchResultsController根据已经创建完的fetch request来创建, 它是NSFetchedResultsController的实例,这个实例的主要任务就是使用fetch request来保证它所关联的数据的新鲜性。创建了fetchResultsController实例后要做一下初始化,一般初始化是向这个控制器发送PerformFetch消息,下面是这一过程的代码。

    - (NSFetchedResultsController *)fetchedResultsController {  
        if (fetchedResultsController != nil) {  
            return fetchedResultsController;  
        }  
        /* 
        Set up the fetched results controller. 
        */  
        // Create the fetch request for the entity.  
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];  
        // Edit the entity name as appropriate.  
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event"  
        inManagedObjectContext:managedObjectContext];  
        [fetchRequest setEntity:entity];  
        // Set the batch size to a suitable number.  
        [fetchRequest setFetchBatchSize:20];  
        // Edit the sort key as appropriate.  
        NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]  
        initWithKey:@"timeStamp" ascending:NO];  
        NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor,nil];  
        [fetchRequest setSortDescriptors:sortDescriptors];  
        // Edit the section name key path and cache name if appropriate.  
        // nil for section name key path means "no sections".  
        NSFetchedResultsController *aFetchedResultsController =  
        [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest  
        managedObjectContext:managedObjectContext sectionNameKeyPath:nil  
        cacheName:@"Root"];  
        aFetchedResultsController.delegate = self;  
        self.fetchedResultsController = aFetchedResultsController;  
        [aFetchedResultsController release];  
        [fetchRequest release];  
        [sortDescriptor release];  
        [sortDescriptors release];  
        return fetchedResultsController;  
    }  

            `这个函数用来创建FetchedResultsController,过程还是比较简单的,下面是初始化这个控制器代码。

    NSError *error = nil;  
    if(![[self  fetchedResultsController]performFetch: &error]){  
        //handle the error appropriately  
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);  
        exit(-1);  
    }  

          这段代码一般会放在viewDidLoad函数中,初始化之后,fetchedResultsController就与数据相连接了,之后要取数据都能直接从这个控制器提供的方法中去取。

            实现这个控制器,最关键的还要实现Fetched Results Controller Delegate Methods。控制器与数据源连接后,控制器监视器会时刻监视着数据源,当数据源发生

改变后,监视器会调用对应的协议方法,改协议总共要实现四个方法,分别为:

    - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller;  
    - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller;  
    - (void)controller:(NSFetchedResultsController *)controller  
       didChangeObject:(id)anObject  
           atIndexPath:(NSIndexPath *)indexPath  
         forChangeType:(NSFetchedResultsChangeType)type  
          newIndexPath:(NSIndexPath *)newIndexPath;  
    - (void)controller:(NSFetchedResultsController *)controller  
      didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo  
               atIndex:(NSUInteger)sectionIndex  
         forChangeType:(NSFetchedResultsChangeType)type;  

              下面依次来解释这四个协议方法。

              1.  - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller

            当控制器监控的数据发生改变时,如对象被删除,有插入,更新等,监视器会在数据发生改变前意识到这个情况,此时就会调用这个函数。往往我们用列表的形式

表现数据,此时意味着屏幕上的数据即将过时,因为数据马上要改变了,这是这个协议方法的工作就是通知列表数据马上要更新的消息,往往代码是这样实现的。
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {  
    [self.tableView beginUpdates];  
} 

           2. - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller

            当fetchedResultsController完成对数据的改变时,监视器会调用这个协议方法。在上面提到的情况,这个方法要通知列表数据已经完成,可以更新显示的数据这个

消息,因此通常的实现是这样的。

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

              didChangeObject:(id)anObject

                        atIndexPath:(NSIndexPath *)indexPath

                  forChangeType:(NSFetchedResultsChangeType)type

                    newIndexPath:(NSIndexPath *)newIndexPath

               当fetchedResultsController发现指定的对象有改变时,监视器会调用这个协议方法。这里改变的类型从列表中体现有 更新、插入、删除或者行的移动。因此这个

方法要实现所有的这些方法,以应对任何一种改变。下面是这个方法的标准实现。

    - (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: {  
                NSString *sectionKeyPath = [controller sectionNameKeyPath];  
                if (sectionKeyPath == nil)  
                    break;  
                NSManagedObject *changedObject = [controller objectAtIndexPath:indexPath];  
                NSArray *keyParts = [sectionKeyPath componentsSeparatedByString:@"."];  
                id currentKeyValue = [changedObject valueForKeyPath:sectionKeyPath];  
                for (int i = 0; i < [keyParts count] - 1; i++) {  
                    NSString *onePart = [keyParts objectAtIndex:i];  
                    changedObject = [changedObject valueForKey:onePart];  
                }  
                sectionKeyPath = [keyParts lastObject];  
                NSDictionary *committedValues = [changedObject committedValuesForKeys:nil];  
                if ([[committedValues valueForKeyPath:sectionKeyPath]isEqual:currentKeyValue])  
                    break;  
                NSUInteger tableSectionCount = [self.tableView numberOfSections];  
                NSUInteger frcSectionCount = [[controller sections] count];  
                if (tableSectionCount != frcSectionCount) {  
                    // Need to insert a section  
                    NSArray *sections = controller.sections;  
                    NSInteger newSectionLocation = -1;  
                    for (id oneSection in sections) {  
                        NSString *sectionName = [oneSection name];  
                        if ([currentKeyValue isEqual:sectionName]) {  
                            newSectionLocation = [sections indexOfObject:oneSection];  
                            break;  
                        }  
                    }  
                    if (newSectionLocation == -1)  
                        return; // uh oh  
                    if (!((newSectionLocation == 0) && (tableSectionCount == 1)  
                           && ([self.tableView numberOfRowsInSection:0] == 0)))  
                        [self.tableView insertSections:[NSIndexSet indexSetWithIndex:newSectionLocation]  
                                      withRowAnimation:UITableViewRowAnimationFade];  
                    NSUInteger indices[2] = {newSectionLocation, 0};  
                    newIndexPath = [[[NSIndexPath alloc] initWithIndexes:indiceslength:2] autorelease];  
                }  
            }  
            case NSFetchedResultsChangeMove  
                if (newIndexPath != nil) {  
                    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]  
                                          withRowAnimation:UITableViewRowAnimationFade];  
                    [self.tableView insertRowsAtIndexPaths: [NSArray arrayWithObject:newIndexPath]  
                                          withRowAnimation: UITableViewRowAnimationRight];  
                }  
                else {  
                    [self.tableView reloadSections:[NSIndexSet  
                    indexSetWithIndex:[indexPath section]]withRowAnimation:UITableViewRowAnimationFade];  
                }  
                break;  
            default:  
                break;  
        }  
    }  


          从上面的代码可以看出,插入,删除,移动是比较简单的,最复杂的是更新。这个代码是xcode的模板代码,基本能适用我们遇到的情况,对更新里面的代码我还不是非常确定,所以这里留着等过几天完全吃透了再补上。

           4. - (void)controller:(NSFetchedResultsController *)controller

            didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo

                                atIndex:(NSUInteger)sectionIndex

                 forChangeType:(NSFetchedResultsChangeType)type

              当改变控制器管理的对象后引起了列表section的变化,此时监视器就会调用这个协议函数。

            下面是标准实现。

    - (void)controller:(NSFetchedResultsController *)controller  
      didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo  
               atIndex:(NSUInteger)sectionIndex  
         forChangeType:(NSFetchedResultsChangeType)type {  
        switch(type) {  
            case NSFetchedResultsChangeInsert:  
                if (!((sectionIndex == 0) && ([self.tableView numberOfSections] == 1)  
                                 && ([self.tableView numberOfRowsInSection:0] == 0)))  
                    [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]  
                                  withRowAnimation:UITableViewRowAnimationFade];  
                break;  
            case NSFetchedResultsChangeDelete:  
                if (!((sectionIndex == 0) && ([self.tableView numberOfSections] == 1)  
                                 && ([self.tableView numberOfRowsInSection:0] == 0)))  
                    [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]  
                                  withRowAnimation:UITableViewRowAnimationFade];  
                break;  
            case NSFetchedResultsChangeMove:  
            case NSFetchedResultsChangeUpdate:  
            default:  
                break;  
        }  
    }  




iOS 数据持久化之CoreData(三)NSFetchedResultsController +Demo

原创Blog,转载请注明出处 blog.csdn.net/hello_hwc 欢饮关注我的iOS SDK详解专栏 http://blog.csdn.net/column/details/huan...
  • Hello_Hwc
  • Hello_Hwc
  • 2015-05-21 09:51:22
  • 2689

CoreData学习笔记(二)

这篇文章重点讲讲CoreData的Fetched Results Controller。              对应的objc类为NSFetchedResultsController。这个类...
  • jinkelei
  • jinkelei
  • 2011-10-13 20:56:42
  • 6190

iOS数据库篇(二)CoreData的创建与使用

  • 2017年06月21日 19:36
  • 46KB
  • 下载

iOS 数据库篇(二) CoreData创建与使用

在上一篇博客iOS 数据库篇(一) CoreData 认识与入门—原理讲解篇,我们了解CoreData是什么,CoreData 的原理,结构以及它的优缺点.这篇文章,我们将会学习 CoreData 的...
  • wanna_dance
  • wanna_dance
  • 2017-06-21 18:05:35
  • 1796

NSFetchedResultsController 与 UITableView 的问题

出错关键字: An exception was caught from the delegate of NSFetchedResultsController during a call to -co...
  • gukong
  • gukong
  • 2014-06-25 20:09:20
  • 1501

iOS Swift教程 Core Data (五)NSFetchedResultsController 下

监视变化 上半部分中,我们已经学习了NSFetchResultsController的3个主要功能中的2个:section和caching,接下来我们学习它的最后一个主要特征,这个特征某种意义上来说...
  • yamingwu
  • yamingwu
  • 2015-01-05 19:19:11
  • 1241

[持续更新]JavaScript学习笔记(二)

1.变量作用域 这个是个重点,也是前端考察的要点。 一个变量的作用域(scope):是程序员代码中定义这个变量的区域。 这是JavaScript权威指南第六版中对作用域的定义。简单的来说:一个变量定义...
  • u014267351
  • u014267351
  • 2015-08-12 22:11:55
  • 405

SpringMVC学习笔记(二): 日常使用功能

七、@RequestBody 和 @ResponseBody (一)@RequestBody: 1、作用: 1)该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMes...
  • u012228718
  • u012228718
  • 2015-01-27 22:43:19
  • 1297

CoreData之FetchRequestController

我目前的理解,CoreData相当于一个综合的数据存储和管理中心,它支持sqlite,二进制存储文件两种形式的数据存储。而CoreData提供了存储管理,包括查询、插入、 删除、更新、回滚、会话管理、...
  • likendsl
  • likendsl
  • 2013-11-14 19:56:38
  • 7462

细数AutoLayout以来UIView和UIViewController新增的相关API

iOS开发里键盘是经常需要打交道的地方,下面为大家带来我整理总结的几种隐藏键盘的方法。 一、隐藏自身软键盘 当对于有多个UITextField控件都想通过点击“Return”来隐藏自身软键盘的情况...
  • u011736319
  • u011736319
  • 2014-10-28 20:16:46
  • 645
收藏助手
不良信息举报
您举报文章:CoreData学习笔记(二)
举报原因:
原因补充:

(最多只允许输入30个字)