CoreData学习笔记(二)

来源:互联网 发布:centos 下安装broadcom 编辑:程序博客网 时间:2024/05/16 11:27

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




原创粉丝点击