咱们的这个联系人列表可以对通讯录中的人进行添加联系人操作,并且可以点击某个联系人,进入详情界面,对联系人的个人信息进行修改并保存,实现一个简单的联系人列表就可以啦!!!
第一步、建一个工程并增加如下的几个类,
1、先创建一个实体类,并增加如下属性,起名为Contacts
2、在我们的主界面ViewController界面创建一个tableView
#import "ViewController.h"
#import "AddViewController.h"
#import "CoreDataHandle.h"
#import "NSString+ChineseToLatin.h"
#import "Contacts.h"
#import "CustomCell.h"
#import "PersonalViewController.h"
@interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tabView;
@property(nonatomic,strong)NSMutableDictionary* allSectionMDic;//所有的分区,该字典的key为分区标题,该字典的值为可变数组,可变数组的元素为联系人对象
//@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
//
//@property (weak, nonatomic) IBOutlet UILabel *phoneLabel;
//@property (weak, nonatomic) IBOutlet UIImageView *headImg;
@end
@implementation ViewController
-(NSMutableDictionary*)allSectionMDic{
if (!_allSectionMDic) {
_allSectionMDic=[[NSMutableDictionary alloc] init];
}
return _allSectionMDic;
}
#pragma mark-------tableView的代理方法
//返回行数
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
//获取字典所有的值,allValuesArray中存储的是字典所有的值,字典的值为可变数组
NSArray* allValuesArray=self.allSectionMDic.allValues;
//取出其中一个分区
NSArray* sectionArray=[allValuesArray objectAtIndex:section];
return sectionArray.count;
}
// 返回行高
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 100;
}
//定义单元格
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
CustomCell* cell=[tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
//获取字典所有的值,allValuesArray中存储的是字典所有的值,字典的值为可变数组
NSArray* allValuesArray=self.allSectionMDic.allValues;
//取出其中一个分区
NSArray* sectionArray=[allValuesArray objectAtIndex:indexPath.section];
//取出联系人
Contacts* contacts=sectionArray[indexPath.row];
cell.headImg.image=[UIImage imageWithData:contacts.headImg];
cell.nameLabel.text=contacts.name;
cell.phoneLabel.text=contacts.phone;
return cell;
}
//返回分区数
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return [self.allSectionMDic allKeys].count;
}
//返回分区标题
-(NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
return [self.allSectionMDic allKeys][section];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.automaticallyAdjustsScrollViewInsets=NO;
NSArray* array=[[CoreDataHandle sharedCoreDataHandle] queryWithEntityName:@"Contacts" predicate:nil sortByAttribute:nil ascending:YES];
[self sectionWithContacts:array];
[self.tabView reloadData];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:@"yf"]) {
//传值
CustomCell* cell=(CustomCell*)sender;
NSIndexPath* path=[self.tabView indexPathForCell:cell];
NSString* key=[self.allSectionMDic allKeys][path.section];
NSArray* array=[self.allSectionMDic objectForKey:key];
Contacts* contacts=array[path.row];
PersonalViewController* personVC=[segue destinationViewController];
personVC.block=^{
//从coreData中获取所有的联系人
CoreDataHandle* coreData=[CoreDataHandle sharedCoreDataHandle];
NSArray* allContacts=[coreData queryWithEntityName:@"Contacts" predicate:nil sortByAttribute:nil ascending:YES];
//将字典中的旧数据清空
if (self.allSectionMDic.count) {
[self.allSectionMDic removeAllObjects];
}
//对获取的联系人按照首字母进行分区处理
[self sectionWithContacts:allContacts];
//刷新数据
[self.tabView reloadData];
};
personVC.contacts=contacts;
}else{
// 在此方法中获取添加联系人的控制器,实现block
UINavigationController* naVC=[segue destinationViewController];
AddViewController* addVC=naVC.childViewControllers.firstObject;
addVC.block=^{
//从coreData中获取所有的联系人
CoreDataHandle* coreData=[CoreDataHandle sharedCoreDataHandle];
NSArray* allContacts=[coreData queryWithEntityName:@"Contacts" predicate:nil sortByAttribute:nil ascending:YES];
//将字典中的旧数据清空
if (self.allSectionMDic.count) {
[self.allSectionMDic removeAllObjects];
}
//对获取的联系人按照首字母进行分区处理
[self sectionWithContacts:allContacts];
//刷新数据
[self.tabView reloadData];
};
}
}
//将联系人动态分区的方法
-(void)sectionWithContacts:(NSArray*)allContacts{
//保证有联系人
if (allContacts && allContacts.count) {
//遍历数组,对每个联系人进行分区
for (Contacts* contacts in allContacts) {
//得到联系人姓名的首字母,根据首字母进行下一步操作
NSString* firstWords=[NSString chineseTransformLettersWihthSourceString:contacts.name];
//一共有两种情况
//第一种是有分区,直接添加;第二种是没有分区,先创建分区再添加。分区就是大字典中的可变数组
NSMutableArray* sectionArray=self.allSectionMDic[firstWords];
if (sectionArray) {
// 说明分区存在
[sectionArray addObject:contacts];
}else{
// 说明分区不存在
sectionArray=[[NSMutableArray alloc] init];
[sectionArray addObject:contacts];
[self.allSectionMDic setObject:sectionArray forKey:firstWords];
}
}
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
3、建一个自定义的cell,继承UITableViewCell
Custom.h中
@property (weak, nonatomic) IBOutlet UIImageView *headImg;
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
@property (weak, nonatomic) IBOutlet UILabel *phoneLabel;
Custom.m中
@implementation CustomCell
- (void)awakeFromNib {
self.headImg.layer.masksToBounds=YES;
self.headImg.layer.cornerRadius=40.0;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
@end
4、创建一个添加联系人界面,起名为AddViewController,在这里进行联系人的添加操作
#import "AddViewController.h"
#import "CoreDataHandle.h"
@interface AddViewController ()<UIImagePickerControllerDelegate,UINavigationControllerDelegate>
- (IBAction)returnBtn:(UIBarButtonItem *)sender;
@property (weak, nonatomic) IBOutlet UIImageView *headImg;
@property (weak, nonatomic) IBOutlet UITextField *nameTF;
@property (weak, nonatomic) IBOutlet UITextField *sexTF;
@property (weak, nonatomic) IBOutlet UITextField *ageTF;
@property (weak, nonatomic) IBOutlet UITextField *phoneTF;
- (IBAction)finishBtn:(UIBarButtonItem *)sender;
- (IBAction)selecePhotoAction:(UITapGestureRecognizer *)sender;
@end
@implementation AddViewController
- (IBAction)returnBtn:(UIBarButtonItem *)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
//完成按钮的点击方法
- (IBAction)finishBtn:(UIBarButtonItem *)sender {
//当内容填充完整的时候要做的操作
if ([self isNull]) {
//将数据存储到CoreData中
CoreDataHandle* coreDataHandle=[CoreDataHandle sharedCoreDataHandle];
NSDictionary* contactDic=@{@"name":self.nameTF.text,@"age":@(self.ageTF.text.intValue),@"sex":self.sexTF.text,@"phone":self.phoneTF.text,@"headImg": UIImageJPEGRepresentation((self.headImg.image), 1.0)};
BOOL isSuccess= [coreDataHandle addDataWithEntityName:@"Contacts" values:@[contactDic]];
if (isSuccess) {
//返回上级界面
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
//通知上级界面刷新界面 block或者协议代理
if (self.block) {
self.block();
}
}else{
NSLog(@"保存数据失败");
}
}
}
//选择照片换头像的方法
- (IBAction)selecePhotoAction:(UITapGestureRecognizer *)sender {
UIImagePickerController* pc=[[UIImagePickerController alloc] init];
pc.allowsEditing=YES;
pc.sourceType=UIImagePickerControllerSourceTypePhotoLibrary;
pc.delegate=self;
[self presentViewController:pc animated:YES completion:nil];
}
//照片选择器的代理方法
//点击取消按钮会执行的代理方法
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
[picker dismissViewControllerAnimated:YES completion:nil];
}
//当我们选择好照片,点击确定按钮会执行的代理方法
//info:存储着我们的多媒体资源
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
//获取图片资源
UIImage* img=nil;
if (picker.allowsEditing) {
// 说明允许编辑图片
img=[info objectForKey:UIImagePickerControllerEditedImage];
}else{
//说明图片不允许被编辑
img=[info objectForKey:UIImagePickerControllerOriginalImage];
}
//将图片显示在imgView上
self.headImg.image=img;
//退出相册
[picker dismissViewControllerAnimated:YES completion:nil];
}
//判断输入框是否有内容
-(BOOL)isNull{
BOOL result=YES;
NSString* msg=@"";
if (self.nameTF.text.length==0) {
result=NO;
msg=@"请输入姓名";
}else if (self.sexTF.text.length==0){
result=NO;
msg=@"请输入性别";
}else if (self.phoneTF.text.length==0){
result=NO;
msg=@"请输入手机号";
}else if (self.ageTF.text.length==0){
result=NO;
msg=@"请输入年龄";
}
if (result) {
return result;
}
[self alertWithMsg:msg];
return result;
}
//警示框
-(void)alertWithMsg:(NSString*)msg{
UIAlertController* alertController=[UIAlertController alertControllerWithTitle:@"友情提示" message:msg preferredStyle:(UIAlertControllerStyleAlert)];
UIAlertAction* action=[UIAlertAction actionWithTitle:@"确定" style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
}];
[alertController addAction:action];
[self presentViewController:alertController animated:YES completion:nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.headImg.layer.masksToBounds=YES;
self.headImg.layer.cornerRadius=50.0;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
5、在创建一个个人界面,起名为PersonalViewController,用来保存个人信息
#import "PersonalViewController.h"
#import "AppDelegate.h"
@interface PersonalViewController ()
- (IBAction)editAction:(UIBarButtonItem *)sender;
@end
@implementation PersonalViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.headImg.layer.masksToBounds=YES;
self.headImg.layer.cornerRadius=50.0;
self.nameTF.text=self.contacts.name;
self.ageTF.text=[NSString stringWithFormat:@"%@",self.contacts.age];
self.phoneTF.text=self.contacts.phone;
self.sexTF.text=self.contacts.sex;
self.headImg.image=[UIImage imageWithData:self.contacts.headImg];
self.view.userInteractionEnabled=NO;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)editAction:(UIBarButtonItem *)sender {
self.view.userInteractionEnabled=!self.view.userInteractionEnabled;
sender.title=self.view.userInteractionEnabled?@"完成":@"编辑";
//当编辑状态为NO的时候,说明点击了完成按钮,我们就对数据进行更改
if (!self.view.userInteractionEnabled) {
self.contacts.headImg=UIImageJPEGRepresentation(self.headImg.image, 1.0);
self.contacts.name=self.nameTF.text;
self.contacts.age=@(self.ageTF.text.intValue);
self.contacts.sex=self.sexTF.text;
self.contacts.phone=self.phoneTF.text;
//同步操作
AppDelegate* appdelegate=[UIApplication sharedApplication].delegate;
[appdelegate saveContext];
if (self.block) {
self.block();
//返回上级界面,上级界面刷新数据
[self.navigationController popViewControllerAnimated:YES];
}
}
}
@end
6、在这里我对CoreData进行了封装,直接用的,这些方法需要在.h中进行声明
#import "CoreDataHandle.h"
@interface CoreDataHandle ()
@property(nonatomic,retain)AppDelegate* appDelegate;
@property(nonatomic,retain)NSManagedObjectContext* context;
@end
@implementation CoreDataHandle
+(CoreDataHandle*)sharedCoreDataHandle{
static CoreDataHandle* coreDataHandle=nil;
if (coreDataHandle==nil) {
coreDataHandle=[[CoreDataHandle alloc] init];
}
return coreDataHandle;
}
//重写属性的getter方法
-(AppDelegate*)appDelegate{
return (AppDelegate*)[UIApplication sharedApplication].delegate;
}
-(NSManagedObjectContext*)context{
return self.appDelegate.managedObjectContext;
}
//增加
-(BOOL)addDataWithEntityName:(NSString*)entityName values:(NSArray<NSDictionary*>*)valuesArray{
//将字符串转换为类名
// Class objectClass=NSClassFromString(entityName);
//创建要插入的被管理者对象
//因为当前是一个公用的coreData处理,所以此处的类型不能写死,用到了多态,父类指针指向子类对象
for (NSDictionary* valueDic in valuesArray) {
NSManagedObject* addData=[NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:self.context];
//当我们父类指针指向子类对象的时候,就不能直接调用子类的属性为它赋值,这时候就需要用到KVC
[addData setValuesForKeysWithDictionary:valueDic];
}
//同步操作
BOOL isSuccess=[[self context] save:nil];
if (isSuccess) {
return YES;
}else{
NSLog(@"同步失败");
return NO;
}
}
//查询 带条件查询
//第一个参数:要查询的实体名
//第二个参数:查询条件 若为nil则查询全表
//第三个参数:按照哪个属性排序 若为nil则不排序
//第四个参数:如果排序 YES:升序 NO:降序
-(NSArray*)queryWithEntityName:(NSString*)entityName
predicate:(NSString*)predicate
sortByAttribute:(NSString*)attributeName
ascending:(BOOL)ascending{
//创建要查询的实体对象
NSFetchRequest* req=[[NSFetchRequest alloc] initWithEntityName:entityName];
//查询条件
if (predicate) {
NSPredicate* myPredicate=[NSPredicate predicateWithFormat:predicate];
req.predicate=myPredicate;
}
//排序
if (attributeName) {
NSSortDescriptor* sort=[NSSortDescriptor sortDescriptorWithKey:attributeName ascending:ascending];
req.sortDescriptors=@[sort];
}
//上下文执行查询操作
NSArray* resultArray=[self.context executeFetchRequest:req error:nil];
return resultArray;
}
//修改数据
//第一个参数:要更改的实体名称
//第二个参数:要被更改的被管理者的范围
//第三个参数:最终要被改成的值
-(BOOL)updataWithEntityName:(NSString*)entityName range:(NSString*)rangeString result:(NSDictionary*)resultDic{
NSArray* resultArray=[self queryWithEntityName:entityName predicate:rangeString sortByAttribute:nil ascending:YES];
//遍历上面数组,将负责条件的所有对象都进行更新
for (NSManagedObject* object in resultArray) {
//遍历字典,将对象中所需要更改的属性值都进行更新
for (NSString* key in resultDic) {
[object setValue:resultDic[key] forKey:key];
}
}
//同步操作
BOOL isSuccess= [[self context] save:nil];
if (isSuccess) {
return YES;
}
NSLog(@"更新失败");
return NO;
}
//删除
-(BOOL)removeObjectWithManageObjects:(NSArray<NSManagedObject*>*)manageObjects{
for (NSManagedObject* item in manageObjects) {
[self.context deleteObject:item];
}
//同步操作
BOOL isSuccess= [[self context] save:nil];
if (isSuccess) {
return YES;
}
NSLog(@"更新失败");
return NO;
}
@end
7、这是一个将汉字转拼音的方法
#import "NSString+ChineseToLatin.h"
@implementation NSString (ChineseToLatin)
//汉字转拼音
+(NSString*)chineseTransformLettersWihthSourceString:(NSString*)sourceString{
//将字符串中的空格替换掉
[sourceString stringByReplacingOccurrencesOfString:@" " withString:@""];
// sourceString = nil;空对象
// sourceString = @"";对象的值为空字符串
//说明字符串对象不为空
if (sourceString && sourceString.length !=0) {
NSMutableString* str = [NSMutableString stringWithString:sourceString];
//将汉字转为字母
//第一个参数:要转换的源字符串
//第二个参数:要转换的范围 如果需要全部转换,此处填写NULL即可
//第三个参数:转换的类型
//第四个参数: YES就是还是得到源字符串 NO得到的是转换好之后的。
//带声调的拼
//__bridge: 当转换类型的时候框架体系发生的改变,不让内存管理方式改变。那么久需要它来修饰类型
CFStringTransform((__bridge CFMutableStringRef)str, NULL, kCFStringTransformToLatin, NO);
NSLog(@"带声调的----%@",str);
//去掉声调
CFStringTransform((__bridge CFMutableStringRef)str, NULL, kCFStringTransformStripCombiningMarks, NO);
NSLog(@"不带声调的----%@",str);
//将拼音大写,截取首字母
NSString* upString = [str uppercaseString];
upString = [upString substringToIndex:1];
//
NSLog(@"大写的首字母----%@",upString);
return upString;
}
//当字符串不存在返回#
return @"#";
}
@end
这样简单的通讯录就完成了运行如下