数据持久化的增删改查
通过 FRC 和 CoreData 动态刷新tabelView 数据
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()<UISearchResultsUpdating,UISearchControllerDelegate,NSFetchedResultsControllerDelegate,UITableViewDataSource,UITableViewDelegate>
@property (weak, nonatomic) IBOutlet UIView *seachView;
@property(nonatomic,strong)UISearchController * searchController;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property(nonatomic,strong)NSManagedObjectContext * managedObjectContext;
@property(nonatomic,strong)NSFetchedResultsController * fetchedResultsController;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self loadShuJu];
[self loadSearch];
}
-(void)viewDidAppear:(BOOL)animated{
[self updateSearchResultsForSearchController:self.searchController];
}
//配置 searchController
-(void)loadSearch
{
self.searchController = [[UISearchController alloc]initWithSearchResultsController:nil];
// 使 searchBar的大小自动适应 searchController 的大小
[self.searchController.searchBar sizeToFit];
// 是否可以在子代视图中显示
self.definesPresentationContext = YES;
// 编辑搜索框时是否隐藏背景
self.searchController.dimsBackgroundDuringPresentation = NO;
// 编辑搜索框时是否隐藏 navigationBar
self.searchController.hidesNavigationBarDuringPresentation = NO;
// 贴视图
[self.seachView addSubview:self.searchController.searchBar];
// 设置代理
self.searchController.searchResultsUpdater = self;
self.searchController.delegate = self;
}
//配置数据
-(void)loadShuJu
{
// 设置代理
self.tableView.dataSource = self;
// 获取上下文
UIApplication * app = [UIApplication sharedApplication];
id delegate = app.delegate;
self.managedObjectContext = [delegate managedObjectContext];
// 通过实体名获取请求
NSFetchRequest * request = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([Person class])];
// 排序规则
NSSortDescriptor * sort1 = [NSSortDescriptor sortDescriptorWithKey:@"firstN" ascending:YES];
NSSortDescriptor * sort2 = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
[request setSortDescriptors:@[sort1,sort2]];
// 请求转化为需要显示的数据
self.fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:request managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"firstN" cacheName:nil];
NSError * error;
// 执行 fetchedResultsController
if (![self.fetchedResultsController performFetch:&error]) {
NSLog(@"%@",error.localizedDescription);
return;
}
// 代理
self.fetchedResultsController.delegate = self;
}
#pragma mark - 配置 tabelView
//section
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return self.fetchedResultsController.sections.count;
}
//每个 section 的行数
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSArray * sections = self.fetchedResultsController.sections;
id<NSFetchedResultsSectionInfo>sectionInfo = sections[section];
return [sectionInfo numberOfObjects];
}
//每个 cell 显示的内容
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Person * person = [self.fetchedResultsController objectAtIndexPath:indexPath];
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
cell.textLabel.text = person.name;
cell.detailTextLabel.text = person.tel;
cell.imageView.image = person.headImg;
return cell;
}
//每个 section 的标题
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSArray * arr = [self.fetchedResultsController sections];
id<NSFetchedResultsSectionInfo>secInfo = arr[section];
return [secInfo name];
}
//一下三个回调配置删除,增加数据(以删除为例)
// 是否可编辑
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete;
}
//点击删除按钮时执行的操作
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
Person * person = [self.fetchedResultsController objectAtIndexPath:indexPath];
[self.managedObjectContext deleteObject:person];
NSError * error;
if (![self.managedObjectContext save:&error]) {
NSLog(@"%@",error.localizedDescription);
return;
}
}
#pragma mark - 配置 searchController 回调
//当搜索框文本变化是执行的操作
-(void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
// 优化代码
if (![[searchController.searchBar text] length]) {
[self loadShuJu];
[self.tableView reloadData];
return;
}
NSFetchRequest * requset = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([Person class])];
// 谓词查询 CONTAINS[cd] 表示包含
// OR 表示‘或’
NSPredicate * predicate = [NSPredicate predicateWithFormat:@"name CONTAINS[cd] %@ OR tel CONTAINS[cd] %@",[self.searchController.searchBar text],[self.searchController.searchBar text]];
[requset setPredicate:predicate];
NSSortDescriptor * sort1 = [NSSortDescriptor sortDescriptorWithKey:@"firstN" ascending:YES];
NSSortDescriptor * sort2 = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
[requset setSortDescriptors:@[sort1,sort2]];
self.fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:requset managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"firstN" cacheName:nil];
NSError * error;
if (![self.fetchedResultsController performFetch:&error]) {
NSLog(@"%@",error.localizedDescription);
return;
}
// 此时 fetchedResultsController 已经变化,但是 tabelView 还没有变化,需要 reloadData 一下
[self.tableView reloadData];
}
//当点击取消搜索时的回调
-(void)didDismissSearchController:(UISearchController *)searchController
{
[self loadShuJu];
[self.tableView reloadData];
}
//点击 cell 进入到编辑页面需要传值
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([sender isKindOfClass:[UITableViewCell class]]) {
NSLog(@"传值");
UITableViewCell * cell = (UITableViewCell *)sender;
NSIndexPath * indexpath = [self.tableView indexPathForCell:cell];
Person * person = [self.fetchedResultsController objectAtIndexPath:indexpath];
UIViewController * view = [segue destinationViewController];
// 下一个 View 应该设置一个属性名为 person (key 的值)的属性用来接收 person
[view setValue:person forKey:@"person"];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// FRC 回调
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.tableView beginUpdates];
}
- (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;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView endUpdates];
}
@end
#import "AddTableViewController.h"
#import "Person.h"
@interface AddTableViewController ()<UIImagePickerControllerDelegate,UIActionSheetDelegate>
@property (weak, nonatomic) IBOutlet UIButton *headImg;
@property (weak, nonatomic) IBOutlet UITextField *lblName;
@property (weak, nonatomic) IBOutlet UITextField *lblTel;
@property(nonatomic,strong)NSManagedObjectContext * managedObjectContext;
@property(nonatomic,strong)Person * person;
@property(nonatomic,strong)UIImagePickerController * picker;
@end
@implementation AddTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self loadShuJu];
}
-(void)loadShuJu
{
UIApplication * app = [UIApplication sharedApplication];
id delegate = app.delegate;
self.managedObjectContext = [delegate managedObjectContext];
// 编辑,添加用的是同一页面,所以需要进行判断
if (self.person) {
self.lblName.text = self.person.name;
self.lblTel.text = self.person.tel;
[self.headImg setImage:self.person.headImg forState:UIControlStateNormal];
[self.managedObjectContext deleteObject:self.person];
NSError * error;
if (![self.managedObjectContext save:&error]) {
NSLog(@"%@",error.localizedDescription);
return;
}
NSLog(@"编辑");
self.title = @"编辑";
}else{
self.title = @"添加联系人";
NSLog(@"联系");
}
}
//界面显示时初始化 UIImagePickerController
-(void)viewDidAppear:(BOOL)animated{
self.picker = [[UIImagePickerController alloc]init];
}
- (IBAction)tapHeadImg:(id)sender {
// UIImagePickerController 代理
self.picker.delegate = self;
UIActionSheet* actionSheet = [[UIActionSheet alloc]
initWithTitle:@"请选择文件来源"
delegate:self
cancelButtonTitle:@"取消"
destructiveButtonTitle:nil
otherButtonTitles:@"照相机",@"摄像机",@"本地相簿",@"本地视频",nil];
[actionSheet showInView:self.view];
}
//通过 actionSheet 选择UIImagePickerController的 type
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
switch (buttonIndex) {
case 0://照相机
{
self.picker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentViewController:self.picker animated:YES completion:nil];
}
break;
case 1://摄像机
{
self.picker.sourceType = UIImagePickerControllerSourceTypeCamera;
self.picker.videoQuality = UIImagePickerControllerQualityTypeLow;
[self presentViewController:self.picker animated:YES completion:nil];
}
break;
case 2://本地相簿
{
self.picker.allowsEditing = YES;
self.picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:self.picker animated:YES completion:nil];
}
break;
case 3://本地视频
{
self.picker.allowsEditing = YES;
self.picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:self.picker animated:YES completion:nil];
}
break;
default:
break;
}
}
// UIImagePickerController 选择完图片时的回调
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
UIImage * image = info[UIImagePickerControllerOriginalImage];
[self.headImg setImage:image forState:UIControlStateNormal];
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)save:(id)sender {
self.person = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([Person class]) inManagedObjectContext:self.managedObjectContext];
self.person.name = self.lblName.text;
self.person.tel = self.lblTel.text;
self.person.headImg = self.headImg.currentImage;
self.person.firstN = self.person.getFirstN;
NSError * error;
if (![self.managedObjectContext save:&error]) {
NSLog(@"%@",error.localizedDescription);
return;
}
// 如果 name 和 Tel 都为空,则删除这条数据(当时想过如果在上一条就进行判断,如果为空则直接不进行保存即可,但是这样在返回到电话簿首页时会显示一条空数据,这条数据没有保存,在下次重启程序时不会显示,这个问题在使用 UITabelViewController 时是不存在的,)
if ((![self.person.name length]) && (![self.person.tel length])) {
[self.managedObjectContext deleteObject:self.person];
NSError * error;
if (![self.managedObjectContext save:&error]) {
NSLog(@"%@",error.localizedDescription);
return;
}
}
// 返回上一界面
[self.navigationController popViewControllerAnimated:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end