NSFetchedResultController与UITableView
1 #import "AppDelegate.h" 2 #import "Book.h" 3 @interface AppDelegate () 4 @end 5 @implementation AppDelegate 6 -(void)addBookWithTitle:(NSString *)title andAuthor:(NSString *)author andPrice:(NSNumber *)price 7 { 8 Book *book = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([Book class]) inManagedObjectContext:self.managedObjectContext]; 9 book.title = title; 10 book.author = author; 11 book.price = price; 12 } 13 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 14 //如果不想每次执行时测试数据都重新插入一遍,可以使用偏好设置,如果已经存在了,就不再进行插入了。 15 NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 16 BOOL isInserted = [userDefaults boolForKey:@"inInserted"]; 17 if (!isInserted) 18 { 19 //插入数据 20 [self addBookWithTitle:@"*文*" andAuthor:@"徐" andPrice:@10000.1]; 21 [self addBookWithTitle:@"西游记" andAuthor:@"吴承恩" andPrice:@20.5]; 22 [self addBookWithTitle:@"水浒传" andAuthor:@"施耐庵" andPrice:@5.1]; 23 [self addBookWithTitle:@"三国演义" andAuthor:@"罗贯中" andPrice:@10.2]; 24 [self addBookWithTitle:@"史记" andAuthor:@"司马迁" andPrice:@45.3]; 25 [self addBookWithTitle:@"资治通鉴" andAuthor:@"司马光" andPrice:@56.5]; 26 [self saveContext]; 27 //保存偏好设置 28 [userDefaults setBool:YES forKey:@"inInserted"]; 29 //自动步更新 30 [userDefaults synchronize]; 31 } 32 return YES; 33 }
1 #import "BookTableViewController.h" 2 #import "Book.h" 3 #import "AppDelegate.h" 4 @interface BookTableViewController ()<NSFetchedResultsControllerDelegate> 5 @property(strong,nonatomic)NSFetchedResultsController *fetchedRC; 6 @property(strong,nonatomic)NSManagedObjectContext *managedObjectContext; 7 @end 8 9 @implementation BookTableViewController 10 11 - (void)viewDidLoad { 12 [super viewDidLoad]; 13 //获取应用代理 14 AppDelegate *delegate = [[UIApplication sharedApplication]delegate]; 15 //本次案例需要对CoreData的内容进行修改,涉及到managedObjectContext,但是magagedObjetContext属于Appdelegate的属性,此处使用协议获取创建新的managedObjectContext; 16 self.managedObjectContext = delegate.managedObjectContext; 17 //使用fetchedRC获取数据 18 NSError *error = nil; 19 [self.fetchedRC performFetch:&error]; 20 if (error) { 21 NSLog(@"NSFetchedResultsController获取数据失败"); 22 } 23 } 24 -(NSFetchedResultsController *)fetchedRC 25 { 26 //判断fetchRC是否存在,如果不存在则创建新的,否则直接返回 27 if (!_fetchedRC) { 28 //使用NSFetchRequest进行获取数据 29 NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([Book class])]; 30 request.fetchBatchSize = 20; 31 //设置以某个字段进行排序,此案例以:price价格大小进行排序 32 NSSortDescriptor *priceSort = [NSSortDescriptor sortDescriptorWithKey:@"price" ascending:YES]; 33 //对获取的数据进行排序 34 [request setSortDescriptors:@[priceSort]]; 35 //创建新的fetchedRC 36 _fetchedRC = [[NSFetchedResultsController alloc]initWithFetchRequest:request managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil]; 37 _fetchedRC.delegate = self; 38 } 39 return _fetchedRC; 40 } 41 42 #pragma mark - Table view data source 43 //设置tableView的分组数 44 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 45 { 46 //分组的数据取决于创建sectionNameKeyPath的设置; 47 return self.fetchedRC.sections.count; 48 } 49 //设置tableView每组有多少行 50 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 51 id sectionsInfo = [self.fetchedRC.sections objectAtIndex:section]; 52 return [sectionsInfo numberOfObjects]; 53 } 54 //自定义方法,设置单元格的显示内容 55 -(void)configCell:(UITableViewCell *)cell andIndexPath:(NSIndexPath *)indexPath 56 { 57 //获取选中的对象 58 Book *book = [self.fetchedRC objectAtIndexPath:indexPath]; 59 cell.textLabel.text = [NSString stringWithFormat:@"%@ %@",book.title,book.author]; 60 cell.detailTextLabel.text = [NSString stringWithFormat:@"%@",book.price]; 61 } 62 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 63 { 64 //1.根据reuseindentifier先到对象池中去找重用的单元格 65 static NSString *reuseIndetifier = @"bookCell"; 66 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIndetifier]; 67 //2.如果没有找到需要自己创建单元格对象 68 if (cell == nil) { 69 cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIndetifier]; 70 } 71 //3.设置单元格对象的内容 72 [self configCell:cell andIndexPath:indexPath]; 73 return cell; 74 } 75 // Override to support conditional editing of the table view. 76 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 77 // Return NO if you do not want the specified item to be editable. 78 return YES; 79 } 80 // Override to support editing the table view. 81 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 82 if (editingStyle == UITableViewCellEditingStyleDelete) 83 { 84 Book *book = [self.fetchedRC objectAtIndexPath:indexPath]; 85 //1.先删除CoreData中的相应数据 86 [self.managedObjectContext deleteObject:book]; 87 //插入新的记录 88 AppDelegate *delegate = [[UIApplication sharedApplication]delegate]; 89 [delegate addBookWithTitle:@"唐诗三百首" andAuthor:@"李白等" andPrice:@12.3]; 90 book.price = @([book.price doubleValue]+10); 91 NSError *error = nil; 92 [self.managedObjectContext save:&error]; 93 if(error) { 94 NSLog(@"失败"); 95 } 96 } else if (editingStyle == UITableViewCellEditingStyleInsert) 97 { 98 } 99 } 100 #pragma mark - NSFetchedResultsController代理方法 101 -(void)controllerWillChangeContent:(NSFetchedResultsController *)controller 102 { 103 [self.tableView beginUpdates]; 104 } 105 -(void)controllerDidChangeContent:(NSFetchedResultsController *)controller 106 { 107 [self.tableView endUpdates]; 108 } 109 /** 110 * 以下方法共进行了两项操作: 111 1.判断操作的类型 112 2.对修改的数据、或新插入的数据位置进行局部刷新 113 */ 114 -(void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath 115 { 116 if (type == NSFetchedResultsChangeDelete)//删除操作 117 { 118 [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 119 } 120 else if (type == NSFetchedResultsChangeInsert)//插入操作 121 { 122 [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 123 } 124 else if (type == NSFetchedResultsChangeUpdate)//更新操作 125 { 126 //首先获取cell; 127 UITableViewCell *cell = [self.fetchedRC objectAtIndexPath:indexPath]; 128 //调用configCell方法 129 [self configCell:cell andIndexPath:indexPath]; 130 //重新加载指定行 131 [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 132 } 133 } 134 @end
运行结果,如下图:
创建控制器
一般来说,你会创建一个NSFetchedResultsController实例作为tableview的成员变量。初始化的时候,你提供四个参数:
1。 一个fetchrequest.必须包含一个sortdescriptor用来给结果集排序。
2。 一个managedobject context。 控制器用这个context来执行取数据的请求。
3。 一个可选的keypath作为sectionname。控制器用keypath来把结果集拆分成各个section。(传nil代表只有一个section)
4。 一个cachefile的名字,用来缓冲数据,生成section和索引信息。
案例中:代码解析
使用fethedRequestController控制器获取数据,此处使用懒加载的方式读取数据:
_fetchedRC = [[NSFetchedResultsController alloc]initWithFetchRequest:request managedObjectContext:self.managedObjectContent sectionNameKeyPath:nil cacheName:@"book"];
参数解析:
参数1 :使用之前需通过NSFetchRequest进行读取数据,然后对request进行排序操作(必须排序你懂不?不排序就出错)。
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([Book class])];
//初始化fetchedRC必须要排序
request.fetchBatchSize = 20;
NSSortDescriptor *priceSort = [NSSortDescriptor sortDescriptorWithKey:@"price" ascending:YES];
//初始化fetchedRC必须要排序
request.fetchBatchSize = 20;
NSSortDescriptor *priceSort = [NSSortDescriptor sortDescriptorWithKey:@"price" ascending:YES];
[request setSortDescriptors:@[priceSort]];
参数2:由于managedObjectContent是在Applelegate.h文件中,如果想要使用,需通过Application协议创建新的managedObjectContent。
//获取应用程序代理
AppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
//如果要对上下文内容进行修改,可managedObjectContent存在于Appdelegate中,须通过协议进行引用。
AppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
//如果要对上下文内容进行修改,可managedObjectContent存在于Appdelegate中,须通过协议进行引用。
self.managedObjectContent = appDelegate.managedObjectContext;
参数3:在tableView中如果不准备进行分组显示,可以将值设为:nil;
参数4:设置缓存。