我们知道 CoreData 里存储的是具有相同结构的一系列数据的集合,TableView 正好是用列表来展示一系列具有相同结构的数据集合的。所以,要是 CoreData 和 TableView 能结合起来,CoreData 查询出来的数据能同步地显示在 TableView 上,更好一点就是 CoreData 里的改动也能同步到 TableView 上,那就再好不过了。可喜的是,确实有这样一个 API,那就是 创建一个简单的 TableView 布局在使用 CoreData 之前,首先我们来创建一个简单的 TableView 布局,对大多数人来说,这应该没什么难度,所以下面就直接贴代码,不会对代码进行解释了。 - (void)viewDidLoad {
[super viewDidLoad];
// 添加编辑和插入按钮
self.navigationItem.leftBarButtonItem = self.editButtonItem;
self.navigationItem.rightBarButtonItem = [self addBarButtonItem];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 100;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier forIndexPath:indexPath];
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// deletions
}
} 这是一个非常简单的 TableView,现在只能显示一些随机生成的数据。接下来我们来实现 初始化 NSFetchedResultsController先来看一下 #pragma mark - NSFetchedResultsController
- (NSFetchedResultsController<Student *> *)fetchedResultsController {
if (!_fetchedResultsController) {
NSFetchRequest *fetchRequest = [Student fetchRequest];
fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@'studentId' ascending:YES]];
fetchRequest.fetchBatchSize = 50;
fetchRequest.fetchLimit = 200;
NSFetchedResultsController *fetchController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.context sectionNameKeyPath:@'studentAge' cacheName:@'StudentTable'];
fetchController.delegate = self;
NSError *error;
[fetchController performFetch:&error];
[[[Logger alloc] init] dealWithError:error whenFail:@'fetch failed' whenSuccess:@'fetch success'];
_fetchedResultsController = fetchController;
}
return _fetchedResultsController;
} 创建 fetchRequest-w600
sectionNameKeyPath-w600
cacheName-w600
除此之外, fetchedResultsController 绑定到 TableView下面来修改 tableView 的 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// sections 是一个 NSFetchedResultsSectionInfo 协议类型的数组,保存着所有 section 的信息
return self.fetchedResultsController.sections.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// sectionInfo 里的 numberOfObjects 属性表示对应 section 里的结果数量
id<NSFetchedResultsSectionInfo> sectionInfo = self.fetchedResultsController.sections[section];
return sectionInfo.numberOfObjects;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIdentifier forIndexPath:indexPath];
// 通过这个方法可以直接获取到对应 indexPath 的实体类对象
Student *student = [self.fetchedResultsController objectAtIndexPath:indexPath];
[self configureCell:cell withStudent:student];
return cell;
}
// 修改后的configureCell 方法
- (void)configureCell:(UITableViewCell *)cell withStudent:(Student *)student {
cell.textLabel.text = [NSString stringWithFormat:@'%d:%@ age:%d', student.studentId, student.studentName, student.studentAge];
} 实现增删改查的同步更新上一步里我们实现了把
typedef NS_ENUM(NSUInteger, NSFetchedResultsChangeType) {
NSFetchedResultsChangeInsert = 1,
NSFetchedResultsChangeDelete = 2,
NSFetchedResultsChangeMove = 3,
NSFetchedResultsChangeUpdate = 4
}
// 对应 indexPath 的数据发生变化时会回调这个方法
@optional
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(nullable NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(nullable NSIndexPath *)newIndexPath;
// section 发生变化时会回调这个方法
@optional
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type;
// 数据内容将要发生变化时会回调
@optional
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller;
// 数据内容发生变化之后会回调
@optional
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller;
// 返回对应 section 的标题
@optional
- (nullable NSString *)controller:(NSFetchedResultsController *)controller sectionIndexTitleForSectionName:(NSString *)sectionName;
@end 想要实现 tableView 的数据同步更新可以按下面的代码来实现这几个 delegate 方法: #pragma mark - NSFetchedResultsControllerDelegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// 在这里调用 beginUpdates 通知 tableView 开始更新,注意要和 endUpdates 联用
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
// beginUpdates 之后,这个方法会调用,根据不同类型,来对tableView进行操作,注意什么时候该用 indexPath,什么时候用 newIndexPath.
switch (type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
case NSFetchedResultsChangeMove:
[self.tableView moveRowAtIndexPath:indexPath toIndexPath:newIndexPath];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[self.tableView cellForRowAtIndexPath:indexPath] withStudent:anObject];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
// 更新完后会回调这里,调用 tableView 的 endUpdates.
[self.tableView endUpdates];
} 最后来实现一开始添加的编辑和插入按钮的操作: - (UIBarButtonItem *)addBarButtonItem {
UIBarButtonItem *addBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addRandomStudent)];
return addBarButtonItem;
}
// 为了看到插入效果,可以把 fetchedResultsController 的fetchLimit 和 fetchBatchSize 调小一些.
- (void)addRandomStudent {
NSString *name = [NSString stringWithFormat:@'student-%u', arc4random_uniform(100000)];
int16_t age = (int16_t)arc4random_uniform(10) 10;
int16_t stuId = (int16_t)arc4random_uniform(INT16_MAX);
Student *student = [NSEntityDescription insertNewObjectForEntityForName:@'Student' inManagedObjectContext:self.context];
student.studentName = name;
student.studentAge = age;
student.studentId = stuId;
[self.context save:nil];
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
Student *student = [self.fetchedResultsController objectAtIndexPath:indexPath];
[self.context deleteObject:student];
[self.context save:nil];
}
} 到此为止 著作权归作者所有
|
|
来自: 永恒clek4xeu0r > 《ios》