IOS開發教程——通訊錄。iOS中帶有一個Contacts應用程序來管理聯系人,但是有些時候我們希望自己的應用能夠訪問或者修改這些信息,這個時候就要用到AddressBook.framework框架。iOS中的通訊錄是存儲在數據庫中的,由於iOS的權限設計,開發人員是不允許直接訪問通訊錄數據庫的,必須依靠AddressBook提供的標准API來實現通訊錄操作。通過AddressBook.framework開發者可以從底層去操作AddressBook.framework的所有信息,但是需要注意的是這個框架是基於C語言編寫的,無法使用ARC來管理內存,開發者需要自己管理內存。下面大致介紹一下通訊錄操作中常用的類型:
ABAddressBookRef:代表通訊錄對象,通過該對象開發人員不用過多的關注通訊錄的存儲方式,可以直接以透明的方式去訪問、保存(在使用AddressBook.framework操作聯系人時,所有的增加、刪除、修改後都必須執行保存操作,類似於Core Data)等。
ABRecordRef:代表一個通用的記錄對象,可以是一條聯系人信息,也可以是一個群組,可以通過ABRecordGetRecordType()函數獲得具體類型。如果作為聯系人(事實上也經常使用它作為聯系人),那麼這個記錄記錄了一個完整的聯系人信息(姓名、性別、電話、郵件等),每條記錄都有一個唯一的ID標示這條記錄(可以通過ABRecordGetRecordID()函數獲得)。
ABPersonRef:代表聯系人信息,很少直接使用,實際開發過程中通常會使用類型為“kABPersonType”的ABRecordRef來表示聯系人(由此可見ABPersonRef其實是一種類型為“kABPersonType”的ABRecordRef)
ABGroupRef:代表群組,與ABPersonRef類似,很少直接使用ABGroupRef,而是使用類型為“kABGroupType”的ABRecordRef來表示群組,一個群組可以包含多個聯系人,一個聯系人也同樣可以多個群組。
由於通訊錄操作的關鍵是對ABRecordRef的操作,首先看一下常用的操作通訊錄記錄的方法:
ABPersonCreate():創建一個類型為“kABPersonType”的ABRecordRef。
ABRecordCopyValue():取得指定屬性的值。
ABRecordCopyCompositeName():取得聯系人(或群組)的復合信息(對於聯系人則包括:姓、名、公司等信息,對於群組則返回組名稱)。
ABRecordSetValue():設置ABRecordRef的屬性值。注意在設置ABRecordRef的值時又分為單值屬性和多值屬性:單值屬性設置只要通過ABRecordSetValue()方法指定屬性名和值即可;多值屬性則要先通過創建一個ABMutableMultiValueRef類型的變量,然後通過ABMultiValueAddValueAndLabel()方法依次添加屬性值,最後通過ABRecordSetValue()方法將ABMutableMultiValueRef類型的變量設置為記錄值。
ABRecordRemoveValue():刪除指定的屬性值。
注意:
由於聯系人訪問時(讀取、設置、刪除時)牽扯到大量聯系人屬性,可以到ABPerson.h中查詢或者直接到幫助文檔“Personal Information Properties”
通訊錄的訪問步驟一般如下:
調用ABAddressBookCreateWithOptions()方法創建通訊錄對象ABAddressBookRef。
調用ABAddressBookRequestAccessWithCompletion()方法獲得用戶授權訪問通訊錄。
調用ABAddressBookCopyArrayOfAllPeople()、ABAddressBookCopyPeopleWithName()方法查詢聯系人信息。
讀取聯系人後如果要顯示聯系人信息則可以調用ABRecord相關方法讀取相應的數據;如果要進行修改聯系人信息,則可以使用對應的方法修改ABRecord信息,然後調用ABAddressBookSave()方法提交修改;如果要刪除聯系人,則可以調用ABAddressBookRemoveRecord()方法刪除,然後調用ABAddressBookSave()提交修改操作。
也就是說如果要修改或者刪除都需要首先查詢對應的聯系人,然後修改或刪除後提交更改。如果用戶要增加一個聯系人則不用進行查詢,直接調用ABPersonCreate()方法創建一個ABRecord然後設置具體的屬性,調用ABAddressBookAddRecord方法添加即可。
下面就通過一個示例演示一下如何通過ABAddressBook.framework訪問通訊錄,這個例子中通過一個UITableViewController模擬一下通訊錄的查看、刪除、添加操作。
主控制器視圖,用於顯示聯系人,修改刪除聯系人:
KCContactViewController.h
//
// KCTableViewController.h
// AddressBook
//
// Created by Kenshin Cui on 14/04/05.
// Copyright (c) 2014年 cmjstudio. All rights reserved.
//
#import
/**
* 定義一個協議作為代理
*/
@protocol KCContactDelegate
//新增或修改聯系人
-(void)editPersonWithFirstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber;
//取消修改或新增
-(void)cancelEdit;
@end
@interface KCContactTableViewController : UITableViewController
@end
KCContactViewController.m
//
// KCTableViewController.m
// AddressBook
//
// Created by Kenshin Cui on 14/04/05.
// Copyright (c) 2014年 cmjstudio. All rights reserved.
//
#import "KCContactTableViewController.h"
#import
#import "KCAddPersonViewController.h"
@interface KCContactTableViewController ()
@property (assign,nonatomic) ABAddressBookRef addressBook;//通訊錄
@property (strong,nonatomic) NSMutableArray *allPerson;//通訊錄所有人員
@property (assign,nonatomic) int isModify;//標識是修改還是新增,通過選擇cell進行導航則認為是修改,否則視為新增
@property (assign,nonatomic) UITableViewCell *selectedCell;//當前選中的單元格
@end
@implementation KCContactTableViewController
#pragma mark - 控制器視圖
- (void)viewDidLoad {
[super viewDidLoad];
//請求訪問通訊錄並初始化數據
[self requestAddressBook];
}
//由於在整個視圖控制器周期內addressBook都駐留在內存中,所有當控制器視圖銷毀時銷毀該對象
-(void)dealloc{
if (self.addressBook!=NULL) {
CFRelease(self.addressBook);
}
}
#pragma mark - UI事件
//點擊刪除按鈕
- (IBAction)trashClick:(UIBarButtonItem *)sender {
self.tableView.editing=!self.tableView.editing;
}
#pragma mark - UITableView數據源方法
- (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);//注意這裡進行了強轉,不用自己釋放資源
NSString *lastName=(__bridge NSString *)ABRecordCopyValue(recordRef, kABPersonLastNameProperty);
ABMultiValueRef phoneNumbersRef= ABRecordCopyValue(recordRef, kABPersonPhoneProperty);//獲取手機號,注意手機號是ABMultiValueRef類,有可能有多條
// NSArray *phoneNumbers=(__bridge NSArray *)ABMultiValueCopyArrayOfAllValues(phoneNumbersRef);//取得CFArraryRef類型的手機記錄並轉化為NSArrary
long count= ABMultiValueGetCount(phoneNumbersRef);
// for(int i=0;i // NSString *phoneLabel= (__bridge NSString *)(ABMultiValueCopyLabelAtIndex(phoneNumbersRef, i));
// NSString *phoneNumber=(__bridge NSString *)(ABMultiValueCopyValueAtIndex(phoneNumbersRef, i));
// NSLog(@"%@:%@",phoneLabel,phoneNumber);
// }
cell.textLabel.text=[NSString stringWithFormat:@"%@ %@",firstName,lastName];
if (count>0) {
cell.detailTextLabel.text=(__bridge NSString *)(ABMultiValueCopyValueAtIndex(phoneNumbersRef, 0));
}
if(ABPersonHasImageData(recordRef)){//如果有照片數據
NSData *imageData= (__bridge NSData *)(ABPersonCopyImageData(recordRef));
cell.imageView.image=[UIImage imageWithData:imageData];
}else{
cell.imageView.image=[UIImage imageNamed:@"avatar"];//沒有圖片使用默認頭像
}
//使用cell的tag存儲記錄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];//從數組移除
[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;
//根據導航控制器取得添加/修改人員的控制器視圖
KCAddPersonViewController *addPersonController=(KCAddPersonViewController *)navigationController.topViewController;
addPersonController.delegate=self;
//如果是通過選擇cell進行的導航操作說明是修改,否則為添加
if (self.isModify) {
UITableViewCell *cell=self.selectedCell;
addPersonController.recordID=(ABRecordID)cell.tag;//設置
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];//重新初始化數據
[self.tableView reloadData];
}
self.isModify=0;
}
-(void)cancelEdit{
self.isModify=0;
}
#pragma mark - 私有方法
/**
* 請求訪問通訊錄
*/
-(void)requestAddressBook{
//創建通訊錄對象
self.addressBook=ABAddressBookCreateWithOptions(NULL, NULL);
//請求訪問用戶通訊錄,注意無論成功與否block都會調用
ABAddressBookRequestAccessWithCompletion(self.addressBook, ^(bool granted, CFErrorRef error) {
if (!granted) {
NSLog(@"未獲得通訊錄訪問權限!");
}
[self initAllPerson];
});
}
/**
* 取得所有通訊錄記錄
*/
-(void)initAllPerson{
//取得通訊錄訪問授權
ABAuthorizationStatus authorization= ABAddressBookGetAuthorizationStatus();
//如果未獲得授權
if (authorization!=kABAuthorizationStatusAuthorized) {
NSLog(@"尚未獲得通訊錄訪問授權!");
return ;
}
//取得通訊錄中所有人員記錄
CFArrayRef allPeople= ABAddressBookCopyArrayOfAllPeople(self.addressBook);
self.allPerson=(__bridge NSMutableArray *)allPeople;
//釋放資源
CFRelease(allPeople);
}
/**
* 刪除指定的記錄
*
* @param recordRef 要刪除的記錄
*/
-(void)removePersonWithRecord:(ABRecordRef)recordRef{
ABAddressBookRemoveRecord(self.addressBook, recordRef, NULL);//刪除
ABAddressBookSave(self.addressBook, NULL);//刪除之後提交更改
}
/**
* 根據姓名刪除記錄
*/
-(void)removePersonWithName:(NSString *)personName{
CFStringRef personNameRef=(__bridge CFStringRef)(personName);
CFArrayRef recordsRef= ABAddressBookCopyPeopleWithName(self.addressBook, personNameRef);//根據人員姓名查找
CFIndex count= CFArrayGetCount(recordsRef);//取得記錄數
for (CFIndex i=0; i ABRecordRef recordRef=CFArrayGetValueAtIndex(recordsRef, i);//取得指定的記錄
ABAddressBookRemoveRecord(self.addressBook, recordRef, NULL);//刪除
}
ABAddressBookSave(self.addressBook, NULL);//刪除之後提交更改
CFRelease(recordsRef);
}
/**
* 添加一條記錄
*
* @param firstName 名
* @param lastName 姓
* @param iPhoneName iPhone手機號
*/
-(void)addPersonWithFirstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber{
//創建一條記錄
ABRecordRef recordRef= ABPersonCreate();
ABRecordSetValue(recordRef, kABPersonFirstNameProperty, (__bridge CFTypeRef)(firstName), NULL);//添加名
ABRecordSetValue(recordRef, kABPersonLastNameProperty, (__bridge CFTypeRef)(lastName), NULL);//添加姓
ABMutableMultiValueRef multiValueRef =ABMultiValueCreateMutable(kABStringPropertyType);//添加設置多值屬性
ABMultiValueAddValueAndLabel(multiValueRef, (__bridge CFStringRef)(workNumber), kABWorkLabel, NULL);//添加工作電話
ABRecordSetValue(recordRef, kABPersonPhoneProperty, multiValueRef, NULL);
//添加記錄
ABAddressBookAddRecord(self.addressBook, recordRef, NULL);
//保存通訊錄,提交更改
ABAddressBookSave(self.addressBook, NULL);
//釋放資源
CFRelease(recordRef);
CFRelease(multiValueRef);
}
/**
* 根據RecordID修改聯系人信息
*
* @param recordID 記錄唯一ID
* @param firstName 姓
* @param lastName 名
* @param homeNumber 工作電話
*/
-(void)modifyPersonWithRecordID:(ABRecordID)recordID firstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber{
ABRecordRef recordRef=ABAddressBookGetPersonWithRecordID(self.addressBook,recordID);
ABRecordSetValue(recordRef, kABPersonFirstNameProperty, (__bridge CFTypeRef)(firstName), NULL);//添加名
ABRecordSetValue(recordRef, kABPersonLastNameProperty, (__bridge CFTypeRef)(lastName), NULL);//添加姓
ABMutableMultiValueRef multiValueRef =ABMultiValueCreateMutable(kABStringPropertyType);
ABMultiValueAddValueAndLabel(multiValueRef, (__bridge CFStringRef)(workNumber), kABWorkLabel, NULL);
ABRecordSetValue(recordRef, kABPersonPhoneProperty, multiValueRef, NULL);
//保存記錄,提交更改
ABAddressBookSave(self.addressBook, NULL);
//釋放資源
CFRelease(multiValueRef);
}
@end
新增或修改控制器視圖,用於顯示一個聯系人的信息或者新增一個聯系人:
KCAddPersonViewController.h
//
// KCAddPersonViewController.h
// AddressBook
//
// kABPersonFirstNameProperty
// Copyright (c) 2014年 cmjstudio. All rights reserved.
//
#import
@protocol KCContactDelegate;
@interface KCAddPersonViewController : UIViewController
@property (assign,nonatomic) int recordID;//通訊錄記錄id,如果ID不為0則代表修改否則認為是新增
@property (strong,nonatomic) NSString *firstNameText;
@property (strong,nonatomic) NSString *lastNameText;
@property (strong,nonatomic) NSString *workPhoneText;
@property (strong,nonatomic) id delegate;
@end
KCAddPersonViewController.m
//
// KCAddPersonViewController.m
// AddressBook
//
// kABPersonFirstNameProperty
// Copyright (c) 2014年 cmjstudio. All rights reserved.
//
#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 {
//調用代理方法
[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則認為是修改,此時需要初始化界面
self.firstName.text=self.firstNameText;
self.lastName.text=self.lastNameText;
self.workPhone.text=self.workPhoneText;
}
}
@end
運行效果:
AddressBook
備注:
1.上文中所指的以Ref結尾的對象事實上是該對象的指針(或引用),在C語言的框架中多數類型會以Ref結尾,這個類型本身就是一個指針,定義時不需要加“*”。
2.通常方法中包含copy、create、new、retain等關鍵字的方法創建的變量使用之後需要調用對應的release方法釋放。例如:使用ABPersonCreate();創建完ABRecordRef變量後使用CFRelease()方法釋放。
3.在與很多C語言框架交互時可以都存在Obj-C和C語言類型之間的轉化(特別是Obj-C和Core Foundation框架中的一些轉化),此時可能會用到橋接,只要在強轉之後前面加上”__bridge”即可,經過橋接轉化後的類型不需要再去手動維護內存,也就不需要使用對應的release方法釋放內存。
4.AddressBook框架中很多類型的創建、屬性設置等都是以這個類型名開發頭的方法來創建的,事實上如果大家熟悉了其他框架會發現也都是類似的,這是Apple開發中約定俗成的命名規則(特別是C語言框架)。例如:要給ABRecordRef類型的變量設置屬性則可以通過ABRecordSetValue()方法完成。
AddressBookUI
使用AddressBook.framework來操作通訊錄特點就是可以對通訊錄有更加精確的控制,但是缺點就是面對大量C語言API稍嫌麻煩,於是Apple官方提供了另一套框架供開發者使用,那就是AddressBookUI.framework。例如前面查看、新增、修改人員的界面這個框架就提供了現成的控制器視圖供開發者使用。下面是這個框架中提供的控制器視圖:
ABPersonViewController:用於查看聯系人信息(可設置編輯)。需要設置displayedPerson屬性來設置要顯示或編輯的聯系人。
ABNewPersonViewController:用於新增聯系人信息。
ABUnknownPersonViewController:用於顯示一個未知聯系人(尚未保存的聯系人)信息。需要設置displayedPerson屬性來設置要顯示的未知聯系人。
以上三個控制器視圖均繼承於UIViewController,在使用過程中必須使用一個UINavigationController進行包裝,否則只能看到視圖內容無法進行操作(例如對於ABNewPersonViewController如果不使用UINavigationController進行包裝則沒有新增和取消按鈕),同時注意包裝後的控制器視圖不需要處理具體新增、修改邏輯(增加和修改的處理邏輯對應的控制器視圖內部已經完成),但是必須處理控制器的關閉操作(調用dismissViewControllerAnimated::方法),並且可以通過代理方法獲得新增、修改的聯系人。下面看一下三個控制器視圖的代理方法:
1.ABPersonViewController的displayViewDelegate代理方法:
-(BOOL)personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier:此方法會在選擇了一個聯系人屬性後觸發,四個參數分別代表:使用的控制器視圖、所查看的聯系人、所選則的聯系人屬性、該屬性是否是多值屬性。
2.ABNewPersonViewController的newPersonViewDelegate代理方法:
-(void)newPersonViewController:(ABNewPersonViewController *)newPersonView didCompleteWithNewPerson:(ABRecordRef)person:點擊取消或完成後觸發,如果參數中的person為NULL說明點擊了取消,否則說明點擊了完成。無論是取消還是完成操作,此方法調用時保存操作已經進行完畢,不需要在此方法中自己保存聯系人信息。
3.ABUnkownPersonViewcontroller的unkownPersonViewDelegate代理方法:
-(void)unknownPersonViewController:(ABUnknownPersonViewController *)unknownCardViewController didResolveToPerson:(ABRecordRef)person:保存此聯系人時調用,調用後將此聯系人返回。
-(BOOL)unknownPersonViewController:(ABUnknownPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier:選擇一個位置聯系人屬性之後執行,返回值代表是否執行默認的選擇操作(例如如果是手機號,默認操作會撥打此電話)
除了上面三類控制器視圖在AddressBookUI中還提供了另外一個控制器視圖ABPeoplePickerNavigationController,它與之前介紹的UIImagePickerController、MPMediaPickerController類似,只是他是用來選擇一個聯系人的。這個控制器視圖本身繼承於UINavigationController,視圖自身的“組”、“取消”按鈕操作不需要開發者來完成(例如開發者不用在點擊取消是關閉當前控制器視圖,它自身已經實現了關閉方法),當然這裡主要說一下這個控制器視圖的peoplePickerDelegate代理方法:
-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person:選擇一個聯系人後執行。此代理方法實現後代理方法“-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier”不會再執行。並且一旦實現了這個代理方法用戶只能選擇到聯系人視圖,無法查看具體聯系人的信息。
-(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker:用戶點擊取消後執行。
-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier:選擇聯系人具體的屬性後執行,注意如果要執行此方法則不能實現-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person代理方法,此時如果點擊一個具體聯系人會導航到聯系人詳細信息界面,用戶點擊具體的屬性後觸發此方法。
下面就看一下上面四個控制器視圖的使用方法,在下面的程序中定義了四個按鈕,點擊不同的按鈕調用不同的控制器視圖用於演示:
//
// ViewController.m
// AddressBookUI
//
// Created by Kenshin Cui on 14/04/05.
// Copyright (c) 2014年 cmjstudio. All rights reserved.
//
#import "ViewController.h"
#import
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
#pragma mark - UI事件
//添加聯系人
- (IBAction)addPersonClick:(UIButton *)sender {
ABNewPersonViewController *newPersonController=[[ABNewPersonViewController alloc]init];
//設置代理
newPersonController.newPersonViewDelegate=self;
//注意ABNewPersonViewController必須包裝一層UINavigationController才能使用,否則不會出現取消和完成按鈕,無法進行保存等操作
UINavigationController *navigationController=[[UINavigationController alloc]initWithRootViewController:newPersonController];
[self presentViewController:navigationController animated:YES completion:nil];
}
//
- (IBAction)unknownPersonClick:(UIButton *)sender {
ABUnknownPersonViewController *unknownPersonController=[[ABUnknownPersonViewController alloc]init];
//設置未知人員
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;
//設置代理
unknownPersonController.unknownPersonViewDelegate=self;
//設置其他屬性
unknownPersonController.allowsActions=YES;//顯示標准操作按鈕
unknownPersonController.allowsAddingToAddressBook=YES;//是否允許將聯系人添加到地址簿
CFRelease(multiValueRef);
CFRelease(recordRef);
//使用導航控制器包裝
UINavigationController *navigationController=[[UINavigationController alloc]initWithRootViewController:unknownPersonController];
[self presentViewController:navigationController animated:YES completion:nil];
}
- (IBAction)showPersonClick:(UIButton *)sender {
ABPersonViewController *personController=[[ABPersonViewController alloc]init];
//設置聯系人
ABAddressBookRef addressBook=ABAddressBookCreateWithOptions(NULL, NULL);
ABRecordRef recordRef= ABAddressBookGetPersonWithRecordID(addressBook, 1);//取得id為1的聯系人記錄
personController.displayedPerson=recordRef;
//設置代理
personController.personViewDelegate=self;
//設置其他屬性
personController.allowsActions=YES;//是否顯示發送信息、共享聯系人等按鈕
personController.allowsEditing=YES;//允許編輯
// personController.displayedProperties=@[@(kABPersonFirstNameProperty),@(kABPersonLastNameProperty)];//顯示的聯系人屬性信息,默認顯示所有信息
//使用導航控制器包裝
UINavigationController *navigationController=[[UINavigationController alloc]initWithRootViewController:personController];
[self presentViewController:navigationController animated:YES completion:nil];
}
- (IBAction)selectPersonClick:(UIButton *)sender {
ABPeoplePickerNavigationController *peoplePickerController=[[ABPeoplePickerNavigationController alloc]init];
//設置代理
peoplePickerController.peoplePickerDelegate=self;
[self presentViewController:peoplePickerController animated:YES completion:nil];
}
#pragma mark - ABNewPersonViewController代理方法
//完成新增(點擊取消和完成按鈕時調用),注意這裡不用做實際的通訊錄增加工作,此代理方法調用時已經完成新增,當保存成功的時候參數中得person會返回保存的記錄,如果點擊取消person為NULL
-(void)newPersonViewController:(ABNewPersonViewController *)newPersonView didCompleteWithNewPerson:(ABRecordRef)person{
//如果有聯系人信息
if (person) {
NSLog(@"%@ 信息保存成功.",(__bridge NSString *)(ABRecordCopyCompositeName(person)));
}else{
NSLog(@"點擊了取消.");
}
//關閉模態視圖窗口
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - ABUnknownPersonViewController代理方法
//保存未知聯系人時觸發
-(void)unknownPersonViewController:(ABUnknownPersonViewController *)unknownCardViewController didResolveToPerson:(ABRecordRef)person{
if (person) {
NSLog(@"%@ 信息保存成功!",(__bridge NSString *)(ABRecordCopyCompositeName(person)));
}
[self dismissViewControllerAnimated:YES completion:nil];
}
//選擇一個人員屬性後觸發,返回值YES表示觸發默認行為操作,否則執行代理中自定義的操作
-(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代理方法
//選擇一個人員屬性後觸發,返回值YES表示觸發默認行為操作,否則執行代理中自定義的操作
-(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代理方法
//選擇一個聯系人後,注意這個代理方法實現後屬性選擇的方法將不會再調用
-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person{
if (person) {
NSLog(@"選擇了%@.",(__bridge NSString *)(ABRecordCopyCompositeName(person)));
}
}
//選擇屬性之後,注意如果上面的代理方法實現後此方法不會被調用
//-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
// if (person && property) {
// NSLog(@"選擇了屬性:%i,值:%@.",property,(__bridge NSString *)ABRecordCopyValue(person, property));
// }
//}
//點擊取消按鈕
-(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker{
NSLog(@"取消選擇.");
}
@end
運行效果:
ABPersonViewController ABNewPersonViewController
ABUnkownPersonViewController ABPeoplePickerNaviagationController