CoreData学习笔记(二)

这篇文章重点讲讲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;  
        }  
    }  




评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值