适用人群:iOS开发。
本文内容:NSFetchedResultsController和UITableView结合适用。
目录:
1.效果图
2.解释
3.代码
1.先上效果图吧:
2.解释
(1)你看着觉得一次性加载这么多数据会不会影响性能。其实呢,NSFetchedResultsController支持对这块的优化,只要设置每次取多少数据, _fetchRequest.fetchBatchSize = 20;,就可以每次从数据库查询20条出来显示,并且效果上看不出任何时间延迟。这个20可自行设置个数,但不要太多。
(2)是不是想问,怎么看NSFetchedResultsController是怎么操作数据库的呢?可以把CoreData操作打印出来,xcode里,打开Edit Scheme...,添加:
-com.apple.CoreData.SQLDebug 1
,如下图:
然后再运行程序,就可以实时看到数据库操作过程。
如下图所示,滑动tableview的时候,会每次从数据库取出20条数据:
(3)并且,当一些数据不可见时,会及时被回收掉,要显示的时候再重新取数据。这样就会避免数据量特别大的时候,严重占据内存。所以啊,用了NSFetchedResultsController后,不用考虑什么分页加载什么的。
3.代码如下:
备注:UserEntityManager只是提供了context。该文件在CoreData基础篇里有介绍。
#import "ViewController.h"
#import "UserEntityManager.h"
@interface ViewController () <UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate>
@property (nonatomic, strong) NSFetchRequest *fetchRequest;
@property (nonatomic, strong) NSFetchedResultsController *fetchController;
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) UserEntityManager *manager;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 添加测试数据
self.manager = [UserEntityManager new];
// [self.manager addDatas];
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
_tableView.dataSource = self;
_tableView.delegate = self;
_tableView.tableFooterView = [UIView new];
[self.view addSubview:_tableView];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"UserEntity" inManagedObjectContext:self.manager.context];
NSSortDescriptor *sd = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sd, nil];
// [request setFetchBatchSize:50];//从数据库里每次加载50条数据来筛选数据
// [request setFetchOffset:10];//读取数据库的游标偏移量,从10开始读取数据
// [request setFetchLimit:10];//每次要取多少条数据,10就是每次从数据库读取10条数据
_fetchRequest = [[NSFetchRequest alloc] init];
[_fetchRequest setEntity:entity];
_fetchRequest.fetchBatchSize = 20;
[_fetchRequest setSortDescriptors:sortDescriptors];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"remark=%@", @"个性签名"];
[_fetchRequest setPredicate:predicate];
_fetchController = [[NSFetchedResultsController alloc] initWithFetchRequest:_fetchRequest managedObjectContext:self.manager.context sectionNameKeyPath:nil cacheName:nil];// 需要区分section的时候,设置sectionNameKeyPath,即为用以区分section的表字段名(或路径),不需要的话置为nil即可。
_fetchController.delegate = self;
BOOL succ = [_fetchController performFetch:nil];
if (succ) {
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// [self.manager addOneData];
});
}
- (void)dealloc {
self.fetchController = nil; // 注意,释放内存
}
#pragma mark - tableView
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if (self.fetchController) {
return [self.fetchController sections].count;
}
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (self.fetchController) {
NSArray *sections = [self.fetchController sections];
id<NSFetchedResultsSectionInfo> sectionInfo = sections[section];
return [sectionInfo numberOfObjects];
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"123"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"123"];
}
UserEntity *user = [self.fetchController objectAtIndexPath:indexPath];
cell.textLabel.text = user.name;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss:SSS";
cell.detailTextLabel.text = [formatter stringFromDate: user.date];
return cell;
}
// row改变
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(nullable NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(nullable NSIndexPath *)newIndexPath {
if (type == NSFetchedResultsChangeInsert) {
[self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (type == NSFetchedResultsChangeDelete) {
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (type == NSFetchedResultsChangeMove) {
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (type == NSFetchedResultsChangeUpdate) {
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
}
- (void)controllerWillChangeContent:(NSFetchedResultsController*)controller {
[self.tableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController*)controller {
[self.tableView endUpdates];
// NSInteger count = self.fetchController.sections[0].numberOfObjects;
// [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:count-1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
// section改变
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
default:
break;
}
}
@end
欢迎留言。