咱們的這個(gè)聯(lián)系人列表可以對(duì)通訊錄中的人進(jìn)行添加聯(lián)系人操作,并且可以點(diǎn)擊某個(gè)聯(lián)系人,進(jìn)入詳情界面,對(duì)聯(lián)系人的個(gè)人信息進(jìn)行修改并保存,實(shí)現(xiàn)一個(gè)簡(jiǎn)單的聯(lián)系人列表就可以啦?。?!
第一步、建一個(gè)工程并增加如下的幾個(gè)類,

屏幕快照 2017-01-20 上午10.21.52.png
1、先創(chuàng)建一個(gè)實(shí)體類,并增加如下屬性,起名為Contacts

屏幕快照 2017-01-20 上午10.28.24.png
2、在我們的主界面ViewController界面創(chuàng)建一個(gè)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;//所有的分區(qū),該字典的key為分區(qū)標(biāo)題,該字典的值為可變數(shù)組,可變數(shù)組的元素為聯(lián)系人對(duì)象
//@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的代理方法
//返回行數(shù)
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
//獲取字典所有的值,allValuesArray中存儲(chǔ)的是字典所有的值,字典的值為可變數(shù)組
NSArray* allValuesArray=self.allSectionMDic.allValues;
//取出其中一個(gè)分區(qū)
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中存儲(chǔ)的是字典所有的值,字典的值為可變數(shù)組
NSArray* allValuesArray=self.allSectionMDic.allValues;
//取出其中一個(gè)分區(qū)
NSArray* sectionArray=[allValuesArray objectAtIndex:indexPath.section];
//取出聯(lián)系人
Contacts* contacts=sectionArray[indexPath.row];
cell.headImg.image=[UIImage imageWithData:contacts.headImg];
cell.nameLabel.text=contacts.name;
cell.phoneLabel.text=contacts.phone;
return cell;
}
//返回分區(qū)數(shù)
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return [self.allSectionMDic allKeys].count;
}
//返回分區(qū)標(biāo)題
-(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中獲取所有的聯(lián)系人
CoreDataHandle* coreData=[CoreDataHandle sharedCoreDataHandle];
NSArray* allContacts=[coreData queryWithEntityName:@"Contacts" predicate:nil sortByAttribute:nil ascending:YES];
//將字典中的舊數(shù)據(jù)清空
if (self.allSectionMDic.count) {
[self.allSectionMDic removeAllObjects];
}
//對(duì)獲取的聯(lián)系人按照首字母進(jìn)行分區(qū)處理
[self sectionWithContacts:allContacts];
//刷新數(shù)據(jù)
[self.tabView reloadData];
};
personVC.contacts=contacts;
}else{
// 在此方法中獲取添加聯(lián)系人的控制器,實(shí)現(xiàn)block
UINavigationController* naVC=[segue destinationViewController];
AddViewController* addVC=naVC.childViewControllers.firstObject;
addVC.block=^{
//從coreData中獲取所有的聯(lián)系人
CoreDataHandle* coreData=[CoreDataHandle sharedCoreDataHandle];
NSArray* allContacts=[coreData queryWithEntityName:@"Contacts" predicate:nil sortByAttribute:nil ascending:YES];
//將字典中的舊數(shù)據(jù)清空
if (self.allSectionMDic.count) {
[self.allSectionMDic removeAllObjects];
}
//對(duì)獲取的聯(lián)系人按照首字母進(jìn)行分區(qū)處理
[self sectionWithContacts:allContacts];
//刷新數(shù)據(jù)
[self.tabView reloadData];
};
}
}
//將聯(lián)系人動(dòng)態(tài)分區(qū)的方法
-(void)sectionWithContacts:(NSArray*)allContacts{
//保證有聯(lián)系人
if (allContacts && allContacts.count) {
//遍歷數(shù)組,對(duì)每個(gè)聯(lián)系人進(jìn)行分區(qū)
for (Contacts* contacts in allContacts) {
//得到聯(lián)系人姓名的首字母,根據(jù)首字母進(jìn)行下一步操作
NSString* firstWords=[NSString chineseTransformLettersWihthSourceString:contacts.name];
//一共有兩種情況
//第一種是有分區(qū),直接添加;第二種是沒有分區(qū),先創(chuàng)建分區(qū)再添加。分區(qū)就是大字典中的可變數(shù)組
NSMutableArray* sectionArray=self.allSectionMDic[firstWords];
if (sectionArray) {
// 說明分區(qū)存在
[sectionArray addObject:contacts];
}else{
// 說明分區(qū)不存在
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、建一個(gè)自定義的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、創(chuàng)建一個(gè)添加聯(lián)系人界面,起名為AddViewController,在這里進(jìn)行聯(lián)系人的添加操作
#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];
}
//完成按鈕的點(diǎn)擊方法
- (IBAction)finishBtn:(UIBarButtonItem *)sender {
//當(dāng)內(nèi)容填充完整的時(shí)候要做的操作
if ([self isNull]) {
//將數(shù)據(jù)存儲(chǔ)到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) {
//返回上級(jí)界面
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
//通知上級(jí)界面刷新界面 block或者協(xié)議代理
if (self.block) {
self.block();
}
}else{
NSLog(@"保存數(shù)據(jù)失敗");
}
}
}
//選擇照片換頭像的方法
- (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];
}
//照片選擇器的代理方法
//點(diǎn)擊取消按鈕會(huì)執(zhí)行的代理方法
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
[picker dismissViewControllerAnimated:YES completion:nil];
}
//當(dāng)我們選擇好照片,點(diǎn)擊確定按鈕會(huì)執(zhí)行的代理方法
//info:存儲(chǔ)著我們的多媒體資源
-(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;
//退出相冊(cè)
[picker dismissViewControllerAnimated:YES completion:nil];
}
//判斷輸入框是否有內(nèi)容
-(BOOL)isNull{
BOOL result=YES;
NSString* msg=@"";
if (self.nameTF.text.length==0) {
result=NO;
msg=@"請(qǐng)輸入姓名";
}else if (self.sexTF.text.length==0){
result=NO;
msg=@"請(qǐng)輸入性別";
}else if (self.phoneTF.text.length==0){
result=NO;
msg=@"請(qǐng)輸入手機(jī)號(hào)";
}else if (self.ageTF.text.length==0){
result=NO;
msg=@"請(qǐng)輸入年齡";
}
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、在創(chuàng)建一個(gè)個(gè)人界面,起名為PersonalViewController,用來保存?zhèn)€人信息
#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?@"完成":@"編輯";
//當(dāng)編輯狀態(tài)為NO的時(shí)候,說明點(diǎn)擊了完成按鈕,我們就對(duì)數(shù)據(jù)進(jìn)行更改
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();
//返回上級(jí)界面,上級(jí)界面刷新數(shù)據(jù)
[self.navigationController popViewControllerAnimated:YES];
}
}
}
@end
6、在這里我對(duì)CoreData進(jìn)行了封裝,直接用的,這些方法需要在.h中進(jìn)行聲明
#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{
//將字符串轉(zhuǎn)換為類名
// Class objectClass=NSClassFromString(entityName);
//創(chuàng)建要插入的被管理者對(duì)象
//因?yàn)楫?dāng)前是一個(gè)公用的coreData處理,所以此處的類型不能寫死,用到了多態(tài),父類指針指向子類對(duì)象
for (NSDictionary* valueDic in valuesArray) {
NSManagedObject* addData=[NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:self.context];
//當(dāng)我們父類指針指向子類對(duì)象的時(shí)候,就不能直接調(diào)用子類的屬性為它賦值,這時(shí)候就需要用到KVC
[addData setValuesForKeysWithDictionary:valueDic];
}
//同步操作
BOOL isSuccess=[[self context] save:nil];
if (isSuccess) {
return YES;
}else{
NSLog(@"同步失敗");
return NO;
}
}
//查詢 帶條件查詢
//第一個(gè)參數(shù):要查詢的實(shí)體名
//第二個(gè)參數(shù):查詢條件 若為nil則查詢?nèi)?//第三個(gè)參數(shù):按照哪個(gè)屬性排序 若為nil則不排序
//第四個(gè)參數(shù):如果排序 YES:升序 NO:降序
-(NSArray*)queryWithEntityName:(NSString*)entityName
predicate:(NSString*)predicate
sortByAttribute:(NSString*)attributeName
ascending:(BOOL)ascending{
//創(chuàng)建要查詢的實(shí)體對(duì)象
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];
}
//上下文執(zhí)行查詢操作
NSArray* resultArray=[self.context executeFetchRequest:req error:nil];
return resultArray;
}
//修改數(shù)據(jù)
//第一個(gè)參數(shù):要更改的實(shí)體名稱
//第二個(gè)參數(shù):要被更改的被管理者的范圍
//第三個(gè)參數(shù):最終要被改成的值
-(BOOL)updataWithEntityName:(NSString*)entityName range:(NSString*)rangeString result:(NSDictionary*)resultDic{
NSArray* resultArray=[self queryWithEntityName:entityName predicate:rangeString sortByAttribute:nil ascending:YES];
//遍歷上面數(shù)組,將負(fù)責(zé)條件的所有對(duì)象都進(jìn)行更新
for (NSManagedObject* object in resultArray) {
//遍歷字典,將對(duì)象中所需要更改的屬性值都進(jìn)行更新
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、這是一個(gè)將漢字轉(zhuǎn)拼音的方法
#import "NSString+ChineseToLatin.h"
@implementation NSString (ChineseToLatin)
//漢字轉(zhuǎn)拼音
+(NSString*)chineseTransformLettersWihthSourceString:(NSString*)sourceString{
//將字符串中的空格替換掉
[sourceString stringByReplacingOccurrencesOfString:@" " withString:@""];
// sourceString = nil;空對(duì)象
// sourceString = @"";對(duì)象的值為空字符串
//說明字符串對(duì)象不為空
if (sourceString && sourceString.length !=0) {
NSMutableString* str = [NSMutableString stringWithString:sourceString];
//將漢字轉(zhuǎn)為字母
//第一個(gè)參數(shù):要轉(zhuǎn)換的源字符串
//第二個(gè)參數(shù):要轉(zhuǎn)換的范圍 如果需要全部轉(zhuǎn)換,此處填寫NULL即可
//第三個(gè)參數(shù):轉(zhuǎn)換的類型
//第四個(gè)參數(shù): YES就是還是得到源字符串 NO得到的是轉(zhuǎn)換好之后的。
//帶聲調(diào)的拼
//__bridge: 當(dāng)轉(zhuǎn)換類型的時(shí)候框架體系發(fā)生的改變,不讓內(nèi)存管理方式改變。那么久需要它來修飾類型
CFStringTransform((__bridge CFMutableStringRef)str, NULL, kCFStringTransformToLatin, NO);
NSLog(@"帶聲調(diào)的----%@",str);
//去掉聲調(diào)
CFStringTransform((__bridge CFMutableStringRef)str, NULL, kCFStringTransformStripCombiningMarks, NO);
NSLog(@"不帶聲調(diào)的----%@",str);
//將拼音大寫,截取首字母
NSString* upString = [str uppercaseString];
upString = [upString substringToIndex:1];
//
NSLog(@"大寫的首字母----%@",upString);
return upString;
}
//當(dāng)字符串不存在返回#
return @"#";
}
@end
這樣簡(jiǎn)單的通訊錄就完成了運(yùn)行如下

](http://upload-images.jianshu.io/upload_images/2758407-2d7860e19f073c5f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)