iOS之短信,郵件,通信錄技術(shù)的完美實(shí)現(xiàn)

前言
今天給大家詳細(xì)介紹一下iOS之短信,郵件,通信錄技術(shù)的具體實(shí)現(xiàn)

  1. 系統(tǒng)應(yīng)用之短信,郵件
    在開(kāi)發(fā)某些應(yīng)用時(shí)可能希望能夠調(diào)用iOS系統(tǒng)內(nèi)置的電話椿访、短信萍嬉、郵件、瀏覽器應(yīng)用密幔,此時(shí)你可以直接使用UIApplication的OpenURL:方法指定特定的協(xié)議來(lái)打開(kāi)不同的系統(tǒng)應(yīng)用富拗。常用的協(xié)議如下:
    打電話:tel:或者tel:臼予、telprompt:或telprompt:(撥打電話前有提示)
    發(fā)短信:sms:或者sms:
    發(fā)送郵件:mailto:或者mailto:
    啟動(dòng)瀏覽器:http:或者h(yuǎn)ttp:
    下面以一個(gè)簡(jiǎn)單的demo演示如何調(diào)用上面幾種系統(tǒng)應(yīng)用:
    #import "ViewController.h"
    @interface ViewController ()
    @end
    @implementation ViewController
    - (void)viewDidLoad {
    [super viewDidLoad];
    }
    #pragma mark - UI事件//打電話
    - (IBAction)callClicK:(UIButton *)sender {
    NSString *phoneNumber=@"18500138888";
    NSString *url=[NSString stringWithFormat:@"tel:%@",phoneNumber];

      //這種方式會(huì)直接撥打電話 
      NSString *url=[NSString stringWithFormat:@"telprompt:%@",phoneNumber];
      //這種方式會(huì)提示用戶確認(rèn)是否撥打電話
     [self openUrl:url];}
    
     //發(fā)送短信
     - (IBAction)sendMessageClick:(UIButton *)sender {
         NSString *phoneNumber=@"18500138888";
         NSString *url=[NSString stringWithFormat:@"sms://%@",phoneNumber]; 
         [self openUrl:url];
     }
    
     //發(fā)送郵件
     - (IBAction)sendEmailClick:(UIButton *)sender {
         NSString *mailAddress=@"kenshin@hotmail.com";
         NSString *url=[NSString stringWithFormat:@"mailto:%@",mailAddress]; [self openUrl:url];
     }
    
     //瀏覽網(wǎng)頁(yè)
     - (IBAction)browserClick:(UIButton *)sender {
         NSString *url=@"http://www.cnblogs.com/kenshincui"; [self openUrl:url];
     }
      #pragma mark - 私有方法
     -(void)openUrl:(NSString *)urlStr{
      //注意url中包含協(xié)議名稱,iOS根據(jù)協(xié)議確定調(diào)用哪個(gè)應(yīng)用啃沪,例如發(fā)送郵件是“sms://”其中“//”可以省略寫成“sms:”(其他協(xié)議也是如此) 
         NSURL *url=[NSURL URLWithString:urlStr]; 
         UIApplication *application=[UIApplication sharedApplication];
         if(![application canOpenURL:url]){ 
             NSLog(@"無(wú)法打開(kāi)\"%@\"粘拾,請(qǐng)確保此應(yīng)用已經(jīng)正確安裝.",url); 
             return;
         } 
         [[UIApplication sharedApplication] openURL:url];
     }
     @end
    

    不難發(fā)現(xiàn)當(dāng)openURL:方法只要指定一個(gè)URL Schame并且已經(jīng)安裝了對(duì)應(yīng)的應(yīng)用程序就可以打開(kāi)此應(yīng)用。當(dāng)然创千,如果是自己開(kāi)發(fā)的應(yīng)用也可以調(diào)用openURL方法來(lái)打開(kāi)缰雇。假設(shè)你現(xiàn)在開(kāi)發(fā)了一個(gè)應(yīng)用A,如果用戶機(jī)器上已經(jīng)安裝了此應(yīng)用追驴,并且在應(yīng)用B中希望能夠直接打開(kāi)A械哟。那么首先需要確保應(yīng)用A已經(jīng)配置了Url Types,具體方法就是在plist文件中添加URL types節(jié)點(diǎn)并配置URL Schemas作為具體協(xié)議殿雪,配置URL identifier作為這個(gè)URL的唯一標(biāo)識(shí)暇咆,如下圖![](http://upload-images.jianshu.io/upload_images/1663804-9d3c0ae6772c3d6b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)然后就可以調(diào)用openURL方法像打開(kāi)系統(tǒng)應(yīng)用一樣打開(kāi)第三方應(yīng)用程序了:

    //打開(kāi)第三方應(yīng)用
    - (IBAction)thirdPartyApplicationClick:(UIButton *)sender { 
     NSString *url=@"cmj://myparams"; 
     [self openUrl:url];
    }
    //就像調(diào)用系統(tǒng)應(yīng)用一樣,協(xié)議后面可以傳遞一些參數(shù)(例如上面?zhèn)鬟f的myparams)冠摄,這樣一來(lái)在應(yīng)用中可以在AppDelegate的
    -(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
    //代理方法中接收參數(shù)并解析糯崎。
     -(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
         NSString *str=[NSString stringWithFormat:@"url:%@,source application:%@,params:%@",url,sourceApplication,[url host]]; 
         NSLog(@"%@",str);
         return YES;//是否打開(kāi)
     }
    
  2. 系統(tǒng)服務(wù)之短信與郵件
    調(diào)用系統(tǒng)內(nèi)置的應(yīng)用來(lái)發(fā)送短信、郵件相當(dāng)簡(jiǎn)單河泳,但是這么操作也存在著一些弊端:當(dāng)你點(diǎn)擊了發(fā)送短信(或郵件)操作之后直接啟動(dòng)了系統(tǒng)的短信(或郵件)應(yīng)用程序沃呢,我們的應(yīng)用其實(shí)此時(shí)已經(jīng)處于一種掛起狀態(tài),發(fā)送完(短信或郵件)之后無(wú)法自動(dòng)回到應(yīng)用界面拆挥。
    如果想要在應(yīng)用程序內(nèi)部完成這些操作則可以利用iOS中的MessageUI.framework,它提供了關(guān)于短信和郵件的UI接口供開(kāi)發(fā)者在應(yīng)用程序內(nèi)部調(diào)用薄霜。從框架名稱不難看出這是一套UI接口,提供有現(xiàn)成的短信和郵件的編輯界面纸兔,開(kāi)發(fā)人員只需要通過(guò)編程的方式給短信和郵件控制器設(shè)置對(duì)應(yīng)的參數(shù)即可惰瓜。

在MessageUI.framework中主要有兩個(gè)控制器類分別用于
發(fā)送短信(MFMessageComposeViewController)
郵件(MFMailComposeViewController),
它們均繼承于UINavigationController。由于兩個(gè)類使用方法十分類似汉矿,這里主要介紹一下MFMessageComposeViewController使用步驟:
*1. 創(chuàng)建MFMessageComposeViewController對(duì)象崎坊。
*2. 設(shè)置收件人recipients、信息正文body洲拇,如果運(yùn)行商支持主題和附件的話可以設(shè)置主題subject奈揍、附件attachments(可以通過(guò)canSendSubject、canSendAttachments方法判斷是否支持)
*3. 設(shè)置代理messageComposeDelegate(注意這里不是delegate屬性赋续,因?yàn)閐elegate屬性已經(jīng)留給UINavigationController男翰,MFMessageComposeViewController沒(méi)有覆蓋此屬性而是重新定義了一個(gè)代理),實(shí)現(xiàn)代理方法獲得發(fā)送狀態(tài)纽乱。

下面自定義一個(gè)發(fā)送短信的界面演示MFMessageComposeViewController的使用:
![](http://upload-images.jianshu.io/upload_images/1663804-91ac5967b31defaa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
用戶通過(guò)在此界面輸入短信信息點(diǎn)擊“發(fā)送信息”調(diào)用MFMessageComposeViewController界面來(lái)展示或進(jìn)一步編輯信息蛾绎,點(diǎn)擊MFMessageComposeViewController中的“發(fā)送”來(lái)完成短信發(fā)送工作,當(dāng)然用戶也可能點(diǎn)擊“取消”按鈕回到前一個(gè)短信編輯頁(yè)面鸦列。
![](http://upload-images.jianshu.io/upload_images/1663804-3e8935df249cb1e3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
實(shí)現(xiàn)代碼:
#import "KCSendMessageViewController.h"
@interface KCSendMessageViewController ()
@property (weak, nonatomic) IBOutlet UITextField *receivers;
@property (weak, nonatomic) IBOutlet UITextField *body;
@property (weak, nonatomic) IBOutlet UITextField subject;
@property (weak, nonatomic) IBOutlet UITextField attachments;
@end@implementation KCSendMessageViewController
#pragma mark - 控制器視圖方法- (void)viewDidLoad { [super viewDidLoad];}#pragma mark - UI事件
- (IBAction)sendMessageClick:(UIButton )sender {
//如果能發(fā)送文本信息
if([MFMessageComposeViewController canSendText]){
MFMessageComposeViewController messageController=[[MFMessageComposeViewController alloc]init];
//收件人
messageController.recipients=[self.receivers.text componentsSeparatedByString:@","];
//信息正文
messageController.body=self.body.text;
//設(shè)置代理,注意這里不是delegate而是messageComposeDelegate
messageController.messageComposeDelegate=self;
//如果運(yùn)行商支持主題
if([MFMessageComposeViewController canSendSubject]){
messageController.subject=self.subject.text;
}
//如果運(yùn)行商支持附件
if ([MFMessageComposeViewController canSendAttachments]) {
/
第一種方法
/ //messageController.attachments=...;
/
第二種方法
/
NSArray *attachments= [self.attachments.text componentsSeparatedByString:@","];
if (attachments.count>0) {
[attachments enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSString path=[[NSBundle mainBundle]pathForResource:obj ofType:nil];
NSURL url=[NSURL fileURLWithPath:path]; [messageController addAttachmentURL:url withAlternateFilename:obj];
}];
}
/
第三種方法
/
NSString *path=[[NSBundle mainBundle]pathForResource:@"photo.jpg" ofType:nil];
NSURL url=[NSURL fileURLWithPath:path];
NSData data=[NSData dataWithContentsOfURL:url];
//
* attatchData:文件數(shù)據(jù) * uti:統(tǒng)一類型標(biāo)識(shí)租冠,標(biāo)識(shí)具體文件類型,詳情查看:幫助文檔中System-Declared Uniform Type Identifiers * fileName:展現(xiàn)給用戶看的文件名稱 */
[messageController addAttachmentData:data typeIdentifier:@"public.image" filename:@"photo.jpg"];
}
[self presentViewController:messageController animated:YES completion:nil];
}}
#pragma mark - MFMessageComposeViewController代理方法
//發(fā)送完成薯嗤,不管成功與否
-(void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result{
switch (result) {
case MessageComposeResultSent: NSLog(@"發(fā)送成功.");
break;
case MessageComposeResultCancelled: NSLog(@"取消發(fā)送.");
break; default: NSLog(@"發(fā)送失敗.");
break; }
[self dismissViewControllerAnimated:YES completion:nil];
}
@end

這里需要強(qiáng)調(diào)一下:
.1) MFMessageComposeViewController的代理不是通過(guò)delegate屬性指定的而是通過(guò)messageComposeDelegate指定的肺稀。
.2) 可以通過(guò)幾種方式來(lái)指定發(fā)送的附件,在這個(gè)過(guò)程中請(qǐng)務(wù)必指定文件的后綴应民,否則在發(fā)送后無(wú)法正確識(shí)別文件類別(例如如果發(fā)送的是一張jpg圖片话原,在發(fā)送后無(wú)法正確查看圖片)。
.3) 無(wú)論發(fā)送成功與否代理方法
-(void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result都會(huì)執(zhí)行诲锹,通過(guò)代理參數(shù)中的result來(lái)獲得發(fā)送狀態(tài)繁仁。
其實(shí)只要熟悉了MFMessageComposeViewController之后,那么用于發(fā)送郵件的MFMailComposeViewController用法和步驟完全一致归园,只是功能不同黄虱。下面看一下MFMailComposeViewController的使用:
#import "KCSendEmailViewController.h"
@interface KCSendEmailViewController ()
@property (weak, nonatomic) IBOutlet UITextField *toTecipients;
//收件人
@property (weak, nonatomic) IBOutlet UITextField *ccRecipients;
//抄送人
@property (weak, nonatomic) IBOutlet UITextField *bccRecipients;
//密送人
@property (weak, nonatomic) IBOutlet UITextField *subject;
//主題
@property (weak, nonatomic) IBOutlet UITextField *body;
//正文
@property (weak, nonatomic) IBOutlet UITextField *attachments;
//附件
@end
@implementation KCSendEmailViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
#pragma mark - UI事件
- (IBAction)sendEmailClick:(UIButton *)sender {
//判斷當(dāng)前是否能夠發(fā)送郵件
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *mailController=[[MFMailComposeViewController alloc]init];
//設(shè)置代理,注意這里不是delegate庸诱,而是mailComposeDelegate
mailController.mailComposeDelegate=self;
//設(shè)置收件人
[mailController setToRecipients:[self.toTecipients.text componentsSeparatedByString:@","]];
//設(shè)置抄送人
if (self.ccRecipients.text.length>0) {
[mailController setCcRecipients:[self.ccRecipients.text componentsSeparatedByString:@","]];
}
//設(shè)置密送人
if (self.bccRecipients.text.length>0) {
[mailController setBccRecipients:[self.bccRecipients.text componentsSeparatedByString:@","]];
}
//設(shè)置主題
[mailController setSubject:self.subject.text];
//設(shè)置內(nèi)容
[mailController setMessageBody:self.body.text isHTML:YES];
//添加附件
if (self.attachments.text.length>0) {
NSArray *attachments=[self.attachments.text componentsSeparatedByString:@","] ;
[attachments enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSString *file=[[NSBundle mainBundle] pathForResource:obj ofType:nil];
NSData *data=[NSData dataWithContentsOfFile:file];
[mailController addAttachmentData:data mimeType:@"image/jpeg" fileName:obj];
//第二個(gè)參數(shù)是mimeType類型捻浦,jpg圖片對(duì)應(yīng)image/jpeg
}];
}
[self presentViewController:mailController animated:YES completion:nil];
}}
#pragma mark - MFMailComposeViewController代理方法
-(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error{
switch (result) {
case MFMailComposeResultSent:
NSLog(@"發(fā)送成功.");
break;
case MFMailComposeResultSaved://如果存儲(chǔ)為草稿(點(diǎn)取消會(huì)提示是否存儲(chǔ)為草稿晤揣,存儲(chǔ)后可以到系統(tǒng)郵件應(yīng)用的對(duì)應(yīng)草稿箱找到)
NSLog(@"郵件已保存.");
break;
case MFMailComposeResultCancelled:
NSLog(@"取消發(fā)送.");
break;
default:
NSLog(@"發(fā)送失敗.");
break;
}
if (error) {
NSLog(@"發(fā)送郵件過(guò)程中發(fā)生錯(cuò)誤,錯(cuò)誤信息:%@",error.localizedDescription);
}
[self dismissViewControllerAnimated:YES completion:nil];
}
@end

運(yùn)行效果:

圖片加載中...

![](http://upload-images.jianshu.io/upload_images/1663804-b9ba36d0596a4f8b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2.2. 通訊錄
iOS中帶有一個(gè)Contacts應(yīng)用程序來(lái)管理聯(lián)系人朱灿,但是有些時(shí)候我們希望自己的應(yīng)用能夠訪問(wèn)或者修改這些信息昧识,這個(gè)時(shí)候就要用到AddressBook.framework框架。
iOS中的通訊錄是存儲(chǔ)在數(shù)據(jù)庫(kù)中的盗扒,由于iOS的權(quán)限設(shè)計(jì)跪楞,開(kāi)發(fā)人員是不允許直接訪問(wèn)通訊錄數(shù)據(jù)庫(kù)的,必須依靠AddressBook提供的標(biāo)準(zhǔn)API來(lái)實(shí)現(xiàn)通訊錄操作侣灶。通過(guò)AddressBook.framework開(kāi)發(fā)者可以從底層去操作AddressBook.framework的所有信息甸祭,但是需要注意的是這個(gè)框架是基于C語(yǔ)言編寫的,無(wú)法使用ARC來(lái)管理內(nèi)存褥影,開(kāi)發(fā)者需要自己管理內(nèi)存池户。下面大致介紹一下通訊錄操作中常用的類型:

.1) ABAddressBookRef:代表通訊錄對(duì)象,通過(guò)該對(duì)象開(kāi)發(fā)人員不用過(guò)多的關(guān)注通訊錄的存儲(chǔ)方式凡怎,可以直接以透明的方式去訪問(wèn)煞檩、保存(在使用AddressBook.framework操作聯(lián)系人時(shí),所有的增加栅贴、刪除斟湃、修改后都必須執(zhí)行保存操作,類似于Core Data)等檐薯。

.2) ABRecordRef:代表一個(gè)通用的記錄對(duì)象凝赛,可以是一條聯(lián)系人信息,也可以是一個(gè)群組坛缕,可以通過(guò)ABRecordGetRecordType()函數(shù)獲得具體類型墓猎。如果作為聯(lián)系人(事實(shí)上也經(jīng)常使用它作為聯(lián)系人),那么這個(gè)記錄記錄了一個(gè)完整的聯(lián)系人信息(姓名赚楚、性別毙沾、電話、郵件等)宠页,每條記錄都有一個(gè)唯一的ID標(biāo)示這條記錄(可以通過(guò)ABRecordGetRecordID()函數(shù)獲得)左胞。

.3) ABPersonRef:代表聯(lián)系人信息,很少直接使用举户,實(shí)際開(kāi)發(fā)過(guò)程中通常會(huì)使用類型為“kABPersonType”的ABRecordRef來(lái)表示聯(lián)系人(由此可見(jiàn)ABPersonRef其實(shí)是一種類型為“kABPersonType”的ABRecordRef)

.4)ABGroupRef:代表群組烤宙,與ABPersonRef類似,很少直接使用ABGroupRef俭嘁,而是使用類型為“kABGroupType”的ABRecordRef來(lái)表示群組躺枕,一個(gè)群組可以包含多個(gè)聯(lián)系人,一個(gè)聯(lián)系人也同樣可以多個(gè)群組。由于通訊錄操作的關(guān)鍵是對(duì)ABRecordRef的操作拐云,首先看一下常用的操作通訊錄記錄的方法:
ABPersonCreate():創(chuàng)建一個(gè)類型為“kABPersonType”的ABRecordRef罢猪。ABRecordCopyValue():取得指定屬性的值。

ABRecordCopyCompositeName():取得聯(lián)系人(或群組)的復(fù)合信息(對(duì)于聯(lián)系人則包括:姓叉瘩、名膳帕、公司等信息,對(duì)于群組則返回組名稱)房揭。
ABRecordSetValue():設(shè)置ABRecordRef的屬性值。注意在設(shè)置ABRecordRef的值時(shí)又分為單值屬性和多值屬性:?jiǎn)沃祵傩栽O(shè)置只要通過(guò)ABRecordSetValue()方法指定屬性名和值即可晌端;多值屬性則要先通過(guò)創(chuàng)建一個(gè)ABMutableMultiValueRef類型的變量捅暴,然后通過(guò)ABMultiValueAddValueAndLabel()方法依次添加屬性值,最后通過(guò)ABRecordSetValue()方法將ABMutableMultiValueRef類型的變量設(shè)置為記錄值咧纠。
ABRecordRemoveValue():刪除指定的屬性值蓬痒。
注意:由于聯(lián)系人訪問(wèn)時(shí)(讀取、設(shè)置漆羔、刪除時(shí))牽扯到大量聯(lián)系人屬性梧奢,可以到ABPerson.h中查詢或者直接到幫助文檔“Personal Information Properties”

通訊錄的訪問(wèn)步驟一般如下:
調(diào)用ABAddressBookCreateWithOptions()方法創(chuàng)建通訊錄對(duì)象ABAddressBookRef。
調(diào)用ABAddressBookRequestAccessWithCompletion()方法獲得用戶授權(quán)訪問(wèn)通訊錄演痒。
調(diào)用ABAddressBookCopyArrayOfAllPeople()亲轨、ABAddressBookCopyPeopleWithName()方法查詢聯(lián)系人信息。
調(diào)用ABAddressBookCopyArrayOfAllPeople()鸟顺、ABAddressBookCopyPeopleWithName()方法查詢聯(lián)系人信息惦蚊。
也就是說(shuō)如果要修改或者刪除都需要首先查詢對(duì)應(yīng)的聯(lián)系人,然后修改或刪除后提交更改讯嫂。如果用戶要增加一個(gè)聯(lián)系人則不用進(jìn)行查詢蹦锋,直接調(diào)用ABPersonCreate()方法創(chuàng)建一個(gè)ABRecord然后設(shè)置具體的屬性,調(diào)用ABAddressBookAddRecord方法添加即可下面就通過(guò)一個(gè)示例演示一下如何通過(guò)ABAddressBook.framework訪問(wèn)通訊錄欧芽,這個(gè)例子中通過(guò)一個(gè)UITableViewController模擬一下通訊錄的查看莉掂、刪除、添加操作千扔。
主控制器視圖憎妙,用于顯示聯(lián)系人,修改刪除聯(lián)系人:

KCContactViewController.h
#import/** * 定義一個(gè)協(xié)議作為代理 */
@protocol KCContactDelegate
//新增或修改聯(lián)系人
-(void)editPersonWithFirstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber;
//取消修改或新增
-(void)cancelEdit;@end@interface KCContactTableViewController : UITableViewController
@end

KCContactViewController.m
#import "KCContactTableViewController.h"
#import "KCAddPersonViewController.h"
@interface KCContactTableViewController ()
@property (assign,nonatomic) ABAddressBookRef addressBook;
//通訊錄
@property (strong,nonatomic) NSMutableArray *allPerson;
//通訊錄所有人員
@property (assign,nonatomic) int isModify;
//標(biāo)識(shí)是修改還是新增曲楚,通過(guò)選擇cell進(jìn)行導(dǎo)航則認(rèn)為是修改尚氛,否則視為新增
@property (assign,nonatomic) UITableViewCell *selectedCell;
//當(dāng)前選中的單元格
@end
@implementation KCContactTableViewController
#pragma mark - 控制器視圖
- (void)viewDidLoad {
     [super viewDidLoad]; 
     //請(qǐng)求訪問(wèn)通訊錄并初始化數(shù)據(jù)
     [self requestAddressBook];
}
//由于在整個(gè)視圖控制器周期內(nèi)addressBook都駐留在內(nèi)存中,所有當(dāng)控制器視圖銷毀時(shí)銷毀該對(duì)象
-(void)dealloc{ 
   if (self.addressBook!=NULL) { 
       CFRelease(self.addressBook); 
    }
}
#pragma mark - UI事件
//點(diǎn)擊刪除按鈕
- (IBAction)trashClick:(UIBarButtonItem *)sender {    
self.tableView.editing=!self.tableView.editing;
}
#pragma mark - UITableView數(shù)據(jù)源方法
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
    return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    return self.allPerson.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    static NSString *identtityKey=@"myTableViewCellIdentityKey1"; 
    UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:identtityKey]; 
    if(cell==nil){ 
        cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identtityKey]; 
    }
    //取得一條人員記錄 
    ABRecordRef recordRef=(__bridge ABRecordRef)self.allPerson[indexPath.row]; 
   //取得記錄中得信息
    NSString *firstName=(__bridge NSString *) ABRecordCopyValue(recordRef, kABPersonFirstNameProperty);
   //注意這里進(jìn)行了強(qiáng)轉(zhuǎn)洞渤,不用自己釋放資源 
    NSString *lastName=(__bridge NSString *)ABRecordCopyValue(recordRef, kABPersonLastNameProperty); 
    ABMultiValueRef phoneNumbersRef= ABRecordCopyValue(recordRef, kABPersonPhoneProperty);
   //獲取手機(jī)號(hào)阅嘶,注意手機(jī)號(hào)是ABMultiValueRef類,有可能有多條//
    NSArray *phoneNumbers=(__bridge NSArray *)ABMultiValueCopyArrayOfAllValues(phoneNumbersRef);
   //取得CFArraryRef類型的手機(jī)記錄并轉(zhuǎn)化為
   NSArrary long count= ABMultiValueGetCount(phoneNumbersRef);
 // 
     for(int i=0;i0) { 
         cell.detailTextLabel.text=(__bridge NSString *)(ABMultiValueCopyValueAtIndex(phoneNumbersRef, 0));
      }
    if(ABPersonHasImageData(recordRef)){
        //如果有照片數(shù)據(jù)
        NSData *imageData= (__bridge NSData *)(ABPersonCopyImageData(recordRef)); 
        cell.imageView.image=[UIImage imageWithData:imageData];
     }else{ 
         cell.imageView.image=[UIImage imageNamed:@"avatar"];
         //沒(méi)有圖片使用默認(rèn)頭像 
    }
    //使用cell的tag存儲(chǔ)記錄id 
    cell.tag=ABRecordGetRecordID(recordRef); 
   return cell;
 }
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 
    if (editingStyle == UITableViewCellEditingStyleDelete) {     
        ABRecordRef recordRef=(__bridge ABRecordRef )self.allPerson[indexPath.row];
        [self removePersonWithRecord:recordRef];
        //從通訊錄刪除
        [self.allPerson removeObjectAtIndex:indexPath.row];
        //從數(shù)組移除
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
        //從列表刪除
     } else if (editingStyle == UITableViewCellEditingStyleInsert) {
      // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
     } 
}
#pragma mark - UITableView代理方法
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ 
    self.isModify=1; 
    self.selectedCell=[tableView cellForRowAtIndexPath:indexPath];
    [self performSegueWithIdentifier:@"AddPerson" sender:self];
}
 #pragma mark - Navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
   if([segue.identifier isEqualToString:@"AddPerson"]){ 
       UINavigationController *navigationController=(UINavigationController *)segue.destinationViewController; 
   //根據(jù)導(dǎo)航控制器取得添加/修改人員的控制器視圖 
   KCAddPersonViewController *addPersonController=(KCAddPersonViewController *)navigationController.topViewController; addPersonController.delegate=self; 
   //如果是通過(guò)選擇cell進(jìn)行的導(dǎo)航操作說(shuō)明是修改,否則為添加 
   if (self.isModify) { 
       UITableViewCell *cell=self.selectedCell; addPersonController.recordID=(ABRecordID)cell.tag;
       //設(shè)置 NSArray *array=[cell.textLabel.text componentsSeparatedByString:@" "];
       if (array.count>0) {
           addPersonController.firstNameText=[array firstObject]; 
       }
       if (array.count>1) {
           addPersonController.lastNameText=[array lastObject]; 
       } 
       addPersonController.workPhoneText=cell.detailTextLabel.text; 
    } 
}}
#pragma mark - KCContact代理方法
-(void)editPersonWithFirstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber{ 
    if (self.isModify) { 
        UITableViewCell *cell=self.selectedCell; NSIndexPath *indexPath= [self.tableView indexPathForCell:cell]; 
        [self modifyPersonWithRecordID:(ABRecordID)cell.tag firstName:firstName lastName:lastName workNumber:workNumber];
        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight]; 
    }else{
        [self addPersonWithFirstName:firstName lastName:lastName workNumber:workNumber];
        //通訊簿中添加信息 
        [self initAllPerson];
        //重新初始化數(shù)據(jù) 
        [self.tableView reloadData];
    } 
    self.isModify=0;
}
-(void)cancelEdit{ 
    self.isModify=0;
}
#pragma mark - 私有方法/** * 請(qǐng)求訪問(wèn)通訊錄 */
-(void)requestAddressBook{
    //創(chuàng)建通訊錄對(duì)象 
    self.addressBook=ABAddressBookCreateWithOptions(NULL, NULL); 
    //請(qǐng)求訪問(wèn)用戶通訊錄,注意無(wú)論成功與否block都會(huì)調(diào)用 
    ABAddressBookRequestAccessWithCompletion(self.addressBook, ^(bool granted, CFErrorRef error) {
       if (!granted) { NSLog(@"未獲得通訊錄訪問(wèn)權(quán)限讯柔!"); 
    }
    [self initAllPerson]; 
   });
}
/** * 取得所有通訊錄記錄 */
-(void)initAllPerson{ 
    //取得通訊錄訪問(wèn)授權(quán) 
    ABAuthorizationStatus authorization= ABAddressBookGetAuthorizationStatus(); 
    //如果未獲得授權(quán) 
    if (authorization!=kABAuthorizationStatusAuthorized) { 
        NSLog(@"尚未獲得通訊錄訪問(wèn)授權(quán)抡蛙!"); 
        return ;
     } 
    //取得通訊錄中所有人員記錄
    CFArrayRef allPeople= ABAddressBookCopyArrayOfAllPeople(self.addressBook); 
    self.allPerson=(__bridge NSMutableArray *)allPeople;
    //釋放資源 CFRelease(allPeople);
}
/** * 刪除指定的記錄 * * @param recordRef 要?jiǎng)h除的記錄 */
-(void)removePersonWithRecord:(ABRecordRef)recordRef{ 
    ABAddressBookRemoveRecord(self.addressBook, recordRef, NULL);
    //刪除 
    ABAddressBookSave(self.addressBook, NULL);
    //刪除之后提交更改
}
/** * 根據(jù)姓名刪除記錄 */
-(void)removePersonWithName:(NSString *)personName{ 
    CFStringRef personNameRef=(__bridge CFStringRef)(personName); 
    CFArrayRef recordsRef= ABAddressBookCopyPeopleWithName(self.addressBook, personNameRef);
    //根據(jù)人員姓名查找 
    CFIndex count= CFArrayGetCount(recordsRef);
    //取得記錄數(shù) for (CFIndex i=0; i

新增或修改控制器視圖,用于顯示一個(gè)聯(lián)系人的信息或者新增一個(gè)聯(lián)系人:
KCAddPersonViewController.h

#import
@protocol KCContactDelegate;
@interface KCAddPersonViewController : UIViewController
@property (assign,nonatomic) int recordID;
//通訊錄記錄id魂迄,如果ID不為0則代表修改否則認(rèn)為是新增
@property (strong,nonatomic) NSString *firstNameText;
@property (strong,nonatomic) NSString *lastNameText;
@property (strong,nonatomic) NSString *workPhoneText;
@property (strong,nonatomic) iddelegate;@end

KCAddPersonViewController.m

#import "KCAddPersonViewController.h"
#import "KCContactTableViewController.h"
@interface KCAddPersonViewController ()
@property (weak, nonatomic) IBOutlet UITextField *firstName;
@property (weak, nonatomic) IBOutlet UITextField *lastName;
@property (weak, nonatomic) IBOutlet UITextField *workPhone;
@end
@implementation KCAddPersonViewController
- (void)viewDidLoad { 
    [super viewDidLoad]; 
    [self setupUI];
}
#pragma mark - UI事件
- (IBAction)cancelClick:(UIBarButtonItem *)sender { 
    [self.delegate cancelEdit]; 
    [self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)doneClick:(UIBarButtonItem *)sender { 
    //調(diào)用代理方法 
    [self.delegate editPersonWithFirstName:self.firstName.text lastName:self.lastName.text workNumber:self.workPhone.text]; 
    [self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - 私有方法
-(void)setupUI{
     if (self.recordID) {
        //如果ID不為0則認(rèn)為是修改粗截,此時(shí)需要初始化界面
        self.firstName.text=self.firstNameText; 
        self.lastName.text=self.lastNameText; 
        self.workPhone.text=self.workPhoneText; 
     }
}
@end

運(yùn)行效果:![](http://upload-images.jianshu.io/upload_images/1663804-aadc436a1d0ba28f.gif?imageMogr2/auto-orient/strip)

備注:
1.上文中所指的以Ref結(jié)尾的對(duì)象事實(shí)上是該對(duì)象的指針(或引用),在C語(yǔ)言的框架中多數(shù)類型會(huì)以Ref結(jié)尾捣炬,這個(gè)類型本身就是一個(gè)指針熊昌,定義時(shí)不需要加“*”。

2.通常方法中包含copy湿酸、create婿屹、new、retain等關(guān)鍵字的方法創(chuàng)建的變量使用之后需要調(diào)用對(duì)應(yīng)的release方法釋放推溃。例如:使用ABPersonCreate();創(chuàng)建完ABRecordRef變量后使用CFRelease()方法釋放昂利。

3.在與很多C語(yǔ)言框架交互時(shí)可以都存在Obj-C和C語(yǔ)言類型之間的轉(zhuǎn)化(特別是Obj-C和Core Foundation框架中的一些轉(zhuǎn)化),此時(shí)可能會(huì)用到橋接铁坎,只要在強(qiáng)轉(zhuǎn)之后前面加上”__bridge”即可蜂奸,經(jīng)過(guò)橋接轉(zhuǎn)化后的類型不需要再去手動(dòng)維護(hù)內(nèi)存,也就不需要使用對(duì)應(yīng)的release方法釋放內(nèi)存硬萍。

4.AddressBook框架中很多類型的創(chuàng)建扩所、屬性設(shè)置等都是以這個(gè)類型名開(kāi)發(fā)頭的方法來(lái)創(chuàng)建的,事實(shí)上如果大家熟悉了其他框架會(huì)發(fā)現(xiàn)也都是類似的朴乖,這是Apple開(kāi)發(fā)中約定俗成的命名規(guī)則(特別是C語(yǔ)言框架)碌奉。例如:要給ABRecordRef類型的變量設(shè)置屬性則可以通過(guò)ABRecordSetValue()方法完成。

AddressBookUI

使用AddressBook.framework來(lái)操作通訊錄特點(diǎn)就是可以對(duì)通訊錄有更加精確的控制寒砖,但是缺點(diǎn)就是面對(duì)大量C語(yǔ)言API稍嫌麻煩赐劣,于是Apple官方提供了另一套框架供開(kāi)發(fā)者使用,那就是AddressBookUI.framework哩都。例如前面查看魁兼、新增、修改人員的界面這個(gè)框架就提供了現(xiàn)成的控制器視圖供開(kāi)發(fā)者使用漠嵌。

下面是這個(gè)框架中提供的控制器視圖:

  1. ABPersonViewController:用于查看聯(lián)系人信息(可設(shè)置編輯)咐汞。需要設(shè)置displayedPerson屬性來(lái)設(shè)置要顯示或編輯的聯(lián)系人。
  2. ABNewPersonViewController:用于新增聯(lián)系人信息儒鹿。
  3. ABUnknownPersonViewController:用于顯示一個(gè)未知聯(lián)系人(尚未保存的聯(lián)系人)信息化撕。需要設(shè)置displayedPerson屬性來(lái)設(shè)置要顯示的未知聯(lián)系人。

以上三個(gè)控制器視圖均繼承于UIViewController约炎,在使用過(guò)程中必須使用一個(gè)UINavigationController進(jìn)行包裝植阴,否則只能看到視圖內(nèi)容無(wú)法進(jìn)行操作(例如對(duì)于ABNewPersonViewController如果不使用UINavigationController進(jìn)行包裝則沒(méi)有新增和取消按鈕)蟹瘾,同時(shí)注意包裝后的控制器視圖不需要處理具體新增、修改邏輯(增加和修改的處理邏輯對(duì)應(yīng)的控制器視圖內(nèi)部已經(jīng)完成)掠手,但是必須處理控制器的關(guān)閉操作(調(diào)用dismissViewControllerAnimated::方法)憾朴,并且可以通過(guò)代理方法獲得新增、修改的聯(lián)系人喷鸽。下面看一下三個(gè)控制器視圖的代理方法:

ABPersonViewController的displayViewDelegate代理方法:

-(BOOL)personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:``(ABMultiValueIdentifier)identifier:
此方法會(huì)在選擇了一個(gè)聯(lián)系人屬性后觸發(fā)众雷,四個(gè)參數(shù)分別代表:使用的控制器視圖、所查看的聯(lián)系人做祝、所選則的聯(lián)系人屬性砾省、該屬性是否是多值屬性。

ABNewPersonViewController的newPersonViewDelegate代理方法:

-(void)newPersonViewController:(ABNewPersonViewController *)newPersonView didCompleteWithNewPerson:(ABRecordRef)person:
 點(diǎn)擊取消或完成后觸發(fā)混槐,如果參數(shù)中的person為NULL說(shuō)明點(diǎn)擊了取消编兄,否則說(shuō)明點(diǎn)擊了完成。無(wú)論是取消還是完成操作纵隔,此方法調(diào)用時(shí)保存操作已經(jīng)進(jìn)行完畢翻诉,不需要在此方法中自己保存聯(lián)系人信息炮姨。

ABUnkownPersonViewcontroller的unkownPersonViewDelegate代理方法:

-(void)unknownPersonViewController:(ABUnknownPersonViewController *)unknownCardViewController didResolveToPerson:(ABRecordRef)person:
保存此聯(lián)系人時(shí)調(diào)用捌刮,調(diào)用后將此聯(lián)系人返回。
-(BOOL)unknownPersonViewController:(ABUnknownPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier:
選擇一個(gè)位置聯(lián)系人屬性之后執(zhí)行舒岸,返回值代表是否執(zhí)行默認(rèn)的選擇操作(例如如果是手機(jī)號(hào)绅作,默認(rèn)操作會(huì)撥打此電話)

除了上面三類控制器視圖在AddressBookUI中還提供了另外一個(gè)控制器視圖ABPeoplePickerNavigationController,它與之前介紹的UIImagePickerController蛾派、MPMediaPickerController類似俄认,只是他是用來(lái)選擇一個(gè)聯(lián)系人的。這個(gè)控制器視圖本身繼承于UINavigationController洪乍,視圖自身的“組”眯杏、“取消”按鈕操作不需要開(kāi)發(fā)者來(lái)完成(例如開(kāi)發(fā)者不用在點(diǎn)擊取消是關(guān)閉當(dāng)前控制器視圖,它自身已經(jīng)實(shí)現(xiàn)了關(guān)閉方法)壳澳,當(dāng)然這里主要說(shuō)一下這個(gè)

控制器視圖的peoplePickerDelegate代理方法:

-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person:
選擇一個(gè)聯(lián)系人后執(zhí)行岂贩。此代理方法實(shí)現(xiàn)后代理方法“
-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier”
不會(huì)再執(zhí)行。并且一旦實(shí)現(xiàn)了這個(gè)代理方法用戶只能選擇到聯(lián)系人視圖巷波,無(wú)法查看具體聯(lián)系人的信息萎津。
-(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker:
用戶點(diǎn)擊取消后執(zhí)行。
-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier:
選擇聯(lián)系人具體的屬性后執(zhí)行抹镊,注意如果要執(zhí)行此方法則不能實(shí)現(xiàn)
-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person
代理方法锉屈,此時(shí)如果點(diǎn)擊一個(gè)具體聯(lián)系人會(huì)導(dǎo)航到聯(lián)系人詳細(xì)信息界面,用戶點(diǎn)擊具體的屬性后觸發(fā)此方法垮耳。

下面就看一下上面四個(gè)控制器視圖的使用方法颈渊,在下面的程序中定義了四個(gè)按鈕遂黍,點(diǎn)擊不同的按鈕調(diào)用不同的控制器視圖用于演示:

#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
     [super viewDidLoad];
}
#pragma mark - UI事件//添加聯(lián)系人
- (IBAction)addPersonClick:(UIButton *)sender { 
    ABNewPersonViewController *newPersonController=[[ABNewPersonViewController alloc]init]; 
    //設(shè)置代理 
    newPersonController.newPersonViewDelegate=self; 
    //注意ABNewPersonViewController必須包裝一層UINavigationController才能使用,否則不會(huì)出現(xiàn)取消和完成按鈕儡炼,無(wú)法進(jìn)行保存等操作 
    UINavigationController *navigationController=[[UINavigationController alloc]initWithRootViewController:newPersonController]; 
    [self presentViewController:navigationController animated:YES completion:nil];
}
- (IBAction)unknownPersonClick:(UIButton *)sender { 
    ABUnknownPersonViewController *unknownPersonController=[[ABUnknownPersonViewController alloc]init]; 
    //設(shè)置未知人員 
    ABRecordRef recordRef=ABPersonCreate(); 
    ABRecordSetValue(recordRef, kABPersonFirstNameProperty, @"Kenshin", NULL); 
    ABRecordSetValue(recordRef, kABPersonLastNameProperty, @"Cui", NULL);
    ABMultiValueRef multiValueRef=ABMultiValueCreateMutable(kABStringPropertyType); 
    ABMultiValueAddValueAndLabel(multiValueRef, @"18500138888", kABHomeLabel, NULL); 
    ABRecordSetValue(recordRef, kABPersonPhoneProperty, multiValueRef, NULL); unknownPersonController.displayedPerson=recordRef; 
    //設(shè)置代理 
    unknownPersonController.unknownPersonViewDelegate=self;
    //設(shè)置其他屬性 
    unknownPersonController.allowsActions=YES;
   //顯示標(biāo)準(zhǔn)操作按鈕 
    unknownPersonController.allowsAddingToAddressBook=YES;
    //是否允許將聯(lián)系人添加到地址簿 
    CFRelease(multiValueRef); 
    CFRelease(recordRef); 
    //使用導(dǎo)航控制器包裝 
    UINavigationController *navigationController=[[UINavigationController alloc]initWithRootViewController:unknownPersonController]; 
    [self presentViewController:navigationController animated:YES completion:nil];
}
- (IBAction)showPersonClick:(UIButton *)sender { 
    ABPersonViewController *personController=[[ABPersonViewController alloc]init]; 
    //設(shè)置聯(lián)系人 ABAddressBookRef addressBook=ABAddressBookCreateWithOptions(NULL, NULL); 
    ABRecordRef recordRef= ABAddressBookGetPersonWithRecordID(addressBook, 1);
    //取得id為1的聯(lián)系人記錄 
    personController.displayedPerson=recordRef; 
    //設(shè)置代理 
    personController.personViewDelegate=self; 
    //設(shè)置其他屬性 
    personController.allowsActions=YES;
    //是否顯示發(fā)送信息妓湘、共享聯(lián)系人等按鈕 
    personController.allowsEditing=YES;
    //允許編輯// 
    personController.displayedProperties=@[@(kABPersonFirstNameProperty),@(kABPersonLastNameProperty)];
    //顯示的聯(lián)系人屬性信息,默認(rèn)顯示所有信息 //使用導(dǎo)航控制器包裝
    UINavigationController *navigationController=[[UINavigationController alloc]initWithRootViewController:personController]; 
    [self presentViewController:navigationController animated:YES completion:nil];
}
- (IBAction)selectPersonClick:(UIButton *)sender { 
    ABPeoplePickerNavigationController *peoplePickerController=[[ABPeoplePickerNavigationController alloc]init]; 
    //設(shè)置代理 
    peoplePickerController.peoplePickerDelegate=self;
    [self presentViewController:peoplePickerController animated:YES completion:nil];
}
#pragma mark - ABNewPersonViewController代理方法//完成新增(點(diǎn)擊取消和完成按鈕時(shí)調(diào)用),注意這里不用做實(shí)際的通訊錄增加工作,此代理方法調(diào)用時(shí)已經(jīng)完成新增乌询,當(dāng)保存成功的時(shí)候參數(shù)中得person會(huì)返回保存的記錄榜贴,如果點(diǎn)擊取消person為NULL
-(void)newPersonViewController:(ABNewPersonViewController *)newPersonView didCompleteWithNewPerson:(ABRecordRef)person{ 
    //如果有聯(lián)系人信息 
    if (person) { 
        NSLog(@"%@ 信息保存成功.",(__bridge NSString *)(ABRecordCopyCompositeName(person))); 
    }else{ 
        NSLog(@"點(diǎn)擊了取消."); 
    }
    //關(guān)閉模態(tài)視圖窗口 
    [self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - ABUnknownPersonViewController代理方法//保存未知聯(lián)系人時(shí)觸發(fā)
-(void)unknownPersonViewController:(ABUnknownPersonViewController *)unknownCardViewController didResolveToPerson:(ABRecordRef)person{
     if (person) { 
        NSLog(@"%@ 信息保存成功!",(__bridge NSString *)(ABRecordCopyCompositeName(person)));
     } 
    [self dismissViewControllerAnimated:YES completion:nil];
}
//選擇一個(gè)人員屬性后觸發(fā)妹田,返回值YES表示觸發(fā)默認(rèn)行為操作唬党,否則執(zhí)行代理中自定義的操作
-(BOOL)unknownPersonViewController:(ABUnknownPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
     if (person) {
         NSLog(@"選擇了屬性:%i,值:%@.",property,(__bridge NSString *)ABRecordCopyValue(person, property)); 
     }
 return NO;
}
#pragma mark - ABPersonViewController代理方法
//選擇一個(gè)人員屬性后觸發(fā)鬼佣,返回值YES表示觸發(fā)默認(rèn)行為操作驶拱,否則執(zhí)行代理中自定義的操作
-(BOOL)personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
    if (person) { 
        NSLog(@"選擇了屬性:%i,值:%@.",property,(__bridge NSString *)ABRecordCopyValue(person, property)); 
     } 
return NO;
}
#pragma mark - ABPeoplePickerNavigationController代理方法//選擇一個(gè)聯(lián)系人后晶衷,注意這個(gè)代理方法實(shí)現(xiàn)后屬性選擇的方法將不會(huì)再調(diào)用
-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person{ 
    if (person) {
        NSLog(@"選擇了%@.",(__bridge NSString *)(ABRecordCopyCompositeName(person)));
    }
}
//選擇屬性之后蓝纲,注意如果上面的代理方法實(shí)現(xiàn)后此方法不會(huì)被調(diào)用//
-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
    // if (person && property) {
       // NSLog(@"選擇了屬性:%i,值:%@.",property,(__bridge NSString *)ABRecordCopyValue(person, property));
    // }
}
//點(diǎn)擊取消按鈕    
-(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker{
     NSLog(@"取消選擇.");
}
@end

![](http://upload-images.jianshu.io/upload_images/1663804-52aeaf5b8ee5d9ac.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

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

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

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

注意:為了讓大家可以更加清楚的看到幾個(gè)控制器視圖的使用晌纫,這里并沒(méi)有結(jié)合前面的UITableViewController來(lái)使用税迷,事實(shí)上大家結(jié)合前面UITableViewController可以做一個(gè)完善的通訊錄應(yīng)用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锹漱,一起剝皮案震驚了整個(gè)濱河市箭养,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌哥牍,老刑警劉巖毕泌,帶你破解...
    沈念sama閱讀 212,599評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異嗅辣,居然都是意外死亡撼泛,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門澡谭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)愿题,“玉大人,你說(shuō)我怎么就攤上這事译暂】偻” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 158,084評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵外永,是天一觀的道長(zhǎng)崎脉。 經(jīng)常有香客問(wèn)我,道長(zhǎng)伯顶,這世上最難降的妖魔是什么囚灼? 我笑而不...
    開(kāi)封第一講書人閱讀 56,708評(píng)論 1 284
  • 正文 為了忘掉前任骆膝,我火速辦了婚禮,結(jié)果婚禮上灶体,老公的妹妹穿的比我還像新娘阅签。我一直安慰自己,他們只是感情好蝎抽,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布政钟。 她就那樣靜靜地躺著,像睡著了一般樟结。 火紅的嫁衣襯著肌膚如雪养交。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 50,021評(píng)論 1 291
  • 那天瓢宦,我揣著相機(jī)與錄音碎连,去河邊找鬼。 笑死驮履,一個(gè)胖子當(dāng)著我的面吹牛鱼辙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播玫镐,決...
    沈念sama閱讀 39,120評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼倒戏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了摘悴?” 一聲冷哼從身側(cè)響起峭梳,我...
    開(kāi)封第一講書人閱讀 37,866評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤舰绘,失蹤者是張志新(化名)和其女友劉穎蹂喻,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體捂寿,經(jīng)...
    沈念sama閱讀 44,308評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡口四,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了秦陋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蔓彩。...
    茶點(diǎn)故事閱讀 38,768評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡戳气,死狀恐怖巾遭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情辅髓,我是刑警寧澤顺又,帶...
    沈念sama閱讀 34,461評(píng)論 4 333
  • 正文 年R本政府宣布更卒,位于F島的核電站,受9級(jí)特大地震影響稚照,放射性物質(zhì)發(fā)生泄漏蹂空。R本人自食惡果不足惜俯萌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望上枕。 院中可真熱鬧咐熙,春花似錦、人聲如沸辨萍。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,850評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)锈玉。三九已至蘸泻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嘲玫,已是汗流浹背悦施。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,082評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留去团,地道東北人抡诞。 一個(gè)月前我還...
    沈念sama閱讀 46,571評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像土陪,于是被迫代替她去往敵國(guó)和親昼汗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • *面試心聲:其實(shí)這些題本人都沒(méi)怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來(lái)就是把...
    Dove_iOS閱讀 27,135評(píng)論 30 470
  • 一鬼雀、系統(tǒng)應(yīng)用 在開(kāi)發(fā)某些應(yīng)用時(shí)顷窒,我們可能希望能夠調(diào)用iOS系統(tǒng)內(nèi)置的電話、短信源哩、郵件鞋吉、瀏覽器應(yīng)用,或者直接調(diào)用安裝...
    執(zhí)著丶執(zhí)念閱讀 1,645評(píng)論 8 25
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理励烦,服務(wù)發(fā)現(xiàn)谓着,斷路器,智...
    卡卡羅2017閱讀 134,637評(píng)論 18 139
  • 中國(guó)股市政策的制定,是以鞏固和加強(qiáng)黨的領(lǐng)導(dǎo)為出發(fā)點(diǎn)的,這是股市政策風(fēng)險(xiǎn)的根源坛掠。保持政權(quán)的穩(wěn)定,是黨和政府的“大局”...
    會(huì)逃跑的小偷閱讀 69評(píng)論 0 0
  • 1:準(zhǔn)備工作 在網(wǎng)頁(yè)http://dev.mysql.com/downloads/mysql/下載Windows ...
    clshinem閱讀 1,042評(píng)論 1 1