iOS开发——高级技术&通讯录服务
通讯录服务
AddressBook
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

1 // 2 // KCTableViewController.h 3 // AddressBook 4 // 5 // Created by Kenshin Cui on 14/04/05. 6 // Copyright (c) 2014年 cmjstudio. All rights reserved. 7 // 8 #import 9 /** 10 * 定义一个协议作为代理 11 */ 12 @protocol KCContactDelegate 13 //新增或修改联系人 14 -(void)editPersonWithFirstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber; 15 //取消修改或新增 16 -(void)cancelEdit; 17 @end 18 @interface KCContactTableViewController : UITableViewController 19 @end

KCContactViewController.m

1 //
2 // KCTableViewController.m
3 // AddressBook
4 //
5 // Created by Kenshin Cui on 14/04/05.
6 // Copyright (c) 2014年 cmjstudio. All rights reserved.
7 //
8 #import "KCContactTableViewController.h"
9 #import
10 #import "KCAddPersonViewController.h"
11 @interface KCContactTableViewController ()
12 @property (assign,nonatomic) ABAddressBookRef addressBook;//通讯录
13 @property (strong,nonatomic) NSMutableArray *allPerson;//通讯录所有人员
14 @property (assign,nonatomic) int isModify;//标识是修改还是新增,通过选择cell进行导航则认为是修改,否则视为新增
15 @property (assign,nonatomic) UITableViewCell *selectedCell;//当前选中的单元格
16 @end
17 @implementation KCContactTableViewController
18 #pragma mark - 控制器视图
19 - (void)viewDidLoad {
20 [super viewDidLoad];
21
22 //请求访问通讯录并初始化数据
23 [self requestAddressBook];
24 }
25 //由于在整个视图控制器周期内addressBook都驻留在内存中,所有当控制器视图销毁时销毁该对象
26 -(void)dealloc{
27 if (self.addressBook!=NULL) {
28 CFRelease(self.addressBook);
29 }
30 }
31 #pragma mark - UI事件
32 //点击删除按钮
33 - (IBAction)trashClick:(UIBarButtonItem *)sender {
34 self.tableView.editing=!self.tableView.editing;
35 }
36 #pragma mark - UITableView数据源方法
37 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
38 return 1;
39 }
40 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
41 return self.allPerson.count;
42 }
43 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
44 static NSString *identtityKey=@"myTableViewCellIdentityKey1";
45 UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:identtityKey];
46 if(cell==nil){
47 cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identtityKey];
48 }
49 //取得一条人员记录
50 ABRecordRef recordRef=(__bridge ABRecordRef)self.allPerson[indexPath.row];
51 //取得记录中得信息
52 NSString *firstName=(__bridge NSString *) ABRecordCopyValue(recordRef, kABPersonFirstNameProperty);//注意这里进行了强转,不用自己释放资源
53 NSString *lastName=(__bridge NSString *)ABRecordCopyValue(recordRef, kABPersonLastNameProperty);
54
55 ABMultiValueRef phoneNumbersRef= ABRecordCopyValue(recordRef, kABPersonPhoneProperty);//获取手机号,注意手机号是ABMultiValueRef类,有可能有多条
56 // NSArray *phoneNumbers=(__bridge NSArray *)ABMultiValueCopyArrayOfAllValues(phoneNumbersRef);//取得CFArraryRef类型的手机记录并转化为NSArrary
57 long count= ABMultiValueGetCount(phoneNumbersRef);
58 // for(int i=0;i0) {
59 cell.detailTextLabel.text=(__bridge NSString *)(ABMultiValueCopyValueAtIndex(phoneNumbersRef, 0));
60 }
61 if(ABPersonHasImageData(recordRef)){//如果有照片数据
62 NSData *imageData= (__bridge NSData *)(ABPersonCopyImageData(recordRef));
63 cell.imageView.image=[UIImage imageWithData:imageData];
64 }else{
65 cell.imageView.image=[UIImage imageNamed:@"avatar"];//没有图片使用默认头像
66 }
67 //使用cell的tag存储记录id
68 cell.tag=ABRecordGetRecordID(recordRef);
69
70 return cell;
71 }
72 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
73 if (editingStyle == UITableViewCellEditingStyleDelete) {
74 ABRecordRef recordRef=(__bridge ABRecordRef )self.allPerson[indexPath.row];
75 [self removePersonWithRecord:recordRef];//从通讯录删除
76 [self.allPerson removeObjectAtIndex:indexPath.row];//从数组移除
77 [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];//从列表删除
78 } else if (editingStyle == UITableViewCellEditingStyleInsert) {
79 // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
80 }
81 }
82 #pragma mark - UITableView代理方法
83 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
84 self.isModify=1;
85 self.selectedCell=[tableView cellForRowAtIndexPath:indexPath];
86 [self performSegueWithIdentifier:@"AddPerson" sender:self];
87 }
88 #pragma mark - Navigation
89 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
90 if([segue.identifier isEqualToString:@"AddPerson"]){
91 UINavigationController *navigationController=(UINavigationController *)segue.destinationViewController;
92 //根据导航控制器取得添加/修改人员的控制器视图
93 KCAddPersonViewController *addPersonController=(KCAddPersonViewController *)navigationController.topViewController;
94 addPersonController.delegate=self;
95 //如果是通过选择cell进行的导航操作说明是修改,否则为添加
96 if (self.isModify) {
97 UITableViewCell *cell=self.selectedCell;
98 addPersonController.recordID=(ABRecordID)cell.tag;//设置
99 NSArray *array=[cell.textLabel.text componentsSeparatedByString:@" "];
100 if (array.count>0) {
101 addPersonController.firstNameText=[array firstObject];
102 }
103 if (array.count>1) {
104 addPersonController.lastNameText=[array lastObject];
105 }
106 addPersonController.workPhoneText=cell.detailTextLabel.text;
107
108 }
109 }
110 }
111 #pragma mark - KCContact代理方法
112 -(void)editPersonWithFirstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber{
113 if (self.isModify) {
114 UITableViewCell *cell=self.selectedCell;
115 NSIndexPath *indexPath= [self.tableView indexPathForCell:cell];
116 [self modifyPersonWithRecordID:(ABRecordID)cell.tag firstName:firstName lastName:lastName workNumber:workNumber];
117 [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight];
118 }else{
119 [self addPersonWithFirstName:firstName lastName:lastName workNumber:workNumber];//通讯簿中添加信息
120 [self initAllPerson];//重新初始化数据
121 [self.tableView reloadData];
122 }
123 self.isModify=0;
124 }
125 -(void)cancelEdit{
126 self.isModify=0;
127 }
128 #pragma mark - 私有方法
129 /**
130 * 请求访问通讯录
131 */
132 -(void)requestAddressBook{
133 //创建通讯录对象
134 self.addressBook=ABAddressBookCreateWithOptions(NULL, NULL);
135
136 //请求访问用户通讯录,注意无论成功与否block都会调用
137 ABAddressBookRequestAccessWithCompletion(self.addressBook, ^(bool granted, CFErrorRef error) {
138 if (!granted) {
139 NSLog(@"未获得通讯录访问权限!");
140 }
141 [self initAllPerson];
142
143 });
144 }
145 /**
146 * 取得所有通讯录记录
147 */
148 -(void)initAllPerson{
149 //取得通讯录访问授权
150 ABAuthorizationStatus authorization= ABAddressBookGetAuthorizationStatus();
151 //如果未获得授权
152 if (authorization!=kABAuthorizationStatusAuthorized) {
153 NSLog(@"尚未获得通讯录访问授权!");
154 return ;
155 }
156 //取得通讯录中所有人员记录
157 CFArrayRef allPeople= ABAddressBookCopyArrayOfAllPeople(self.addressBook);
158 self.allPerson=(__bridge NSMutableArray *)allPeople;
159
160 //释放资源
161 CFRelease(allPeople);
162 }
163 /**
164 * 删除指定的记录
165 *
166 * @param recordRef 要删除的记录
167 */
168 -(void)removePersonWithRecord:(ABRecordRef)recordRef{
169 ABAddressBookRemoveRecord(self.addressBook, recordRef, NULL);//删除
170 ABAddressBookSave(self.addressBook, NULL);//删除之后提交更改
171 }
172 /**
173 * 根据姓名删除记录
174 */
175 -(void)removePersonWithName:(NSString *)personName{
176 CFStringRef personNameRef=(__bridge CFStringRef)(personName);
177 CFArrayRef recordsRef= ABAddressBookCopyPeopleWithName(self.addressBook, personNameRef);//根据人员姓名查找
178 CFIndex count= CFArrayGetCount(recordsRef);//取得记录数
179 for (CFIndex i=0; i!=count; ++i) {
180 ABRecordRef recordRef=CFArrayGetValueAtIndex(recordsRef, i);//取得指定的记录
181 ABAddressBookRemoveRecord(self.addressBook, recordRef, NULL);//删除
182 }
183 ABAddressBookSave(self.addressBook, NULL);//删除之后提交更改
184 CFRelease(recordsRef);
185 }
186 /**
187 * 添加一条记录
188 *
189 * @param firstName 名
190 * @param lastName 姓
191 * @param iPhoneName iPhone手机号
192 */
193 -(void)addPersonWithFirstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber{
194 //创建一条记录
195 ABRecordRef recordRef= ABPersonCreate();
196 ABRecordSetValue(recordRef, kABPersonFirstNameProperty, (__bridge CFTypeRef)(firstName), NULL);//添加名
197 ABRecordSetValue(recordRef, kABPersonLastNameProperty, (__bridge CFTypeRef)(lastName), NULL);//添加姓
198
199 ABMutableMultiValueRef multiValueRef =ABMultiValueCreateMutable(kABStringPropertyType);//添加设置多值属性
200 ABMultiValueAddValueAndLabel(multiValueRef, (__bridge CFStringRef)(workNumber), kABWorkLabel, NULL);//添加工作电话
201 ABRecordSetValue(recordRef, kABPersonPhoneProperty, multiValueRef, NULL);
202
203 //添加记录
204 ABAddressBookAddRecord(self.addressBook, recordRef, NULL);
205
206 //保存通讯录,提交更改
207 ABAddressBookSave(self.addressBook, NULL);
208 //释放资源
209 CFRelease(recordRef);
210 CFRelease(multiValueRef);
211 }
212 /**
213 * 根据RecordID修改联系人信息
214 *
215 * @param recordID 记录唯一ID
216 * @param firstName 姓
217 * @param lastName 名
218 * @param homeNumber 工作电话
219 */
220 -(void)modifyPersonWithRecordID:(ABRecordID)recordID firstName:(NSString *)firstName lastName:(NSString *)lastName workNumber:(NSString *)workNumber{
221 ABRecordRef recordRef=ABAddressBookGetPersonWithRecordID(self.addressBook,recordID);
222 ABRecordSetValue(recordRef, kABPersonFirstNameProperty, (__bridge CFTypeRef)(firstName), NULL);//添加名
223 ABRecordSetValue(recordRef, kABPersonLastNameProperty, (__bridge CFTypeRef)(lastName), NULL);//添加姓
224
225 ABMutableMultiValueRef multiValueRef =ABMultiValueCreateMutable(kABStringPropertyType);
226 ABMultiValueAddValueAndLabel(multiValueRef, (__bridge CFStringRef)(workNumber), kABWorkLabel, NULL);
227 ABRecordSetValue(recordRef, kABPersonPhoneProperty, multiValueRef, NULL);
228 //保存记录,提交更改
229 ABAddressBookSave(self.addressBook, NULL);
230 //释放资源
231 CFRelease(multiValueRef);
232 }
233 @end

新增或修改控制器视图,用于显示一个联系人的信息或者新增一个联系人:
KCAddPersonViewController.h

1 // 2 // KCAddPersonViewController.h 3 // AddressBook 4 // 5 // kABPersonFirstNameProperty 6 // Copyright (c) 2014年 cmjstudio. All rights reserved. 7 // 8 #import 9 @protocol KCContactDelegate; 10 @interface KCAddPersonViewController : UIViewController 11 @property (assign,nonatomic) int recordID;//通讯录记录id,如果ID不为0则代表修改否则认为是新增 12 @property (strong,nonatomic) NSString *firstNameText; 13 @property (strong,nonatomic) NSString *lastNameText; 14 @property (strong,nonatomic) NSString *workPhoneText; 15 @property (strong,nonatomic) iddelegate; 16 @end


1 //
2 // KCAddPersonViewController.m
3 // AddressBook
4 //
5 // kABPersonFirstNameProperty
6 // Copyright (c) 2014年 cmjstudio. All rights reserved.
7 //
8 #import "KCAddPersonViewController.h"
9 #import "KCContactTableViewController.h"
10 @interface KCAddPersonViewController ()
11 @property (weak, nonatomic) IBOutlet UITextField *firstName;
12 @property (weak, nonatomic) IBOutlet UITextField *lastName;
13 @property (weak, nonatomic) IBOutlet UITextField *workPhone;
14 @end
15 @implementation KCAddPersonViewController
16 - (void)viewDidLoad {
17 [super viewDidLoad];
18 [self setupUI];
19 }
20 #pragma mark - UI事件
21 - (IBAction)cancelClick:(UIBarButtonItem *)sender {
22 [self.delegate cancelEdit];
23 [self dismissViewControllerAnimated:YES completion:nil];
24 }
25 - (IBAction)doneClick:(UIBarButtonItem *)sender {
26 //调用代理方法
27 [self.delegate editPersonWithFirstName:self.firstName.text lastName:self.lastName.text workNumber:self.workPhone.text];
28
29 [self dismissViewControllerAnimated:YES completion:nil];
30 }
31 #pragma mark - 私有方法
32 -(void)setupUI{
33 if (self.recordID) {//如果ID不为0则认为是修改,此时需要初始化界面
34 self.firstName.text=self.firstNameText;
35 self.lastName.text=self.lastNameText;
36 self.workPhone.text=self.workPhoneText;
37 }
38 }
39 @end

KCAddPersonViewController.m
运行效果:

备注:
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代理方法,此时如果点击一个具体联系人会导航到联系人详细信息界面,用户点击具 体的属性后触发此方法。
下面就看一下上面四个控制器视图的使用方法,在下面的程序中定义了四个按钮,点击不同的按钮调用不同的控制器视图用于演示:

1 //
2 // ViewController.m
3 // AddressBookUI
4 //
5 // Created by Kenshin Cui on 14/04/05.
6 // Copyright (c) 2014年 cmjstudio. All rights reserved.
7 //
8 #import "ViewController.h"
9 #import
10 @interface ViewController ()
11 @end
12 @implementation ViewController
13 - (void)viewDidLoad {
14 [super viewDidLoad];
15 }
16 #pragma mark - UI事件
17 //添加联系人
18 - (IBAction)addPersonClick:(UIButton *)sender {
19 ABNewPersonViewController *newPersonController=[[ABNewPersonViewController alloc]init];
20 //设置代理
21 newPersonController.newPersonViewDelegate=self;
22 //注意ABNewPersonViewController必须包装一层UINavigationController才能使用,否则不会出现取消和完成按钮,无法进行保存等操作
23 UINavigationController *navigationController=[[UINavigationController alloc]initWithRootViewController:newPersonController];
24 [self presentViewController:navigationController animated:YES completion:nil];
25 }
26 //
27 - (IBAction)unknownPersonClick:(UIButton *)sender {
28 ABUnknownPersonViewController *unknownPersonController=[[ABUnknownPersonViewController alloc]init];
29 //设置未知人员
30 ABRecordRef recordRef=ABPersonCreate();
31 ABRecordSetValue(recordRef, kABPersonFirstNameProperty, @"Kenshin", NULL);
32 ABRecordSetValue(recordRef, kABPersonLastNameProperty, @"Cui", NULL);
33 ABMultiValueRef multiValueRef=ABMultiValueCreateMutable(kABStringPropertyType);
34 ABMultiValueAddValueAndLabel(multiValueRef, @"18500138888", kABHomeLabel, NULL);
35 ABRecordSetValue(recordRef, kABPersonPhoneProperty, multiValueRef, NULL);
36 unknownPersonController.displayedPerson=recordRef;
37 //设置代理
38 unknownPersonController.unknownPersonViewDelegate=self;
39 //设置其他属性
40 unknownPersonController.allowsActions=YES;//显示标准操作按钮
41 unknownPersonController.allowsAddingToAddressBook=YES;//是否允许将联系人添加到地址簿
42
43 CFRelease(multiValueRef);
44 CFRelease(recordRef);
45 //使用导航控制器包装
46 UINavigationController *navigationController=[[UINavigationController alloc]initWithRootViewController:unknownPersonController];
47 [self presentViewController:navigationController animated:YES completion:nil];
48 }
49 - (IBAction)showPersonClick:(UIButton *)sender {
50 ABPersonViewController *personController=[[ABPersonViewController alloc]init];
51 //设置联系人
52 ABAddressBookRef addressBook=ABAddressBookCreateWithOptions(NULL, NULL);
53 ABRecordRef recordRef= ABAddressBookGetPersonWithRecordID(addressBook, 1);//取得id为1的联系人记录
54 personController.displayedPerson=recordRef;
55 //设置代理
56 personController.personViewDelegate=self;
57 //设置其他属性
58 personController.allowsActions=YES;//是否显示发送信息、共享联系人等按钮
59 personController.allowsEditing=YES;//允许编辑
60 // personController.displayedProperties=@[@(kABPersonFirstNameProperty),@(kABPersonLastNameProperty)];//显示的联系人属性信息,默认显示所有信息
61
62 //使用导航控制器包装
63 UINavigationController *navigationController=[[UINavigationController alloc]initWithRootViewController:personController];
64 [self presentViewController:navigationController animated:YES completion:nil];
65 }
66 - (IBAction)selectPersonClick:(UIButton *)sender {
67 ABPeoplePickerNavigationController *peoplePickerController=[[ABPeoplePickerNavigationController alloc]init];
68 //设置代理
69 peoplePickerController.peoplePickerDelegate=self;
70 [self presentViewController:peoplePickerController animated:YES completion:nil];
71 }
72 #pragma mark - ABNewPersonViewController代理方法
73 //完成新增(点击取消和完成按钮时调用),注意这里不用做实际的通讯录增加工作,此代理方法调用时已经完成新增,当保存成功的时候参数中得person会返回保存的记录,如果点击取消person为NULL
74 -(void)newPersonViewController:(ABNewPersonViewController *)newPersonView didCompleteWithNewPerson:(ABRecordRef)person{
75 //如果有联系人信息
76 if (person) {
77 NSLog(@"%@ 信息保存成功.",(__bridge NSString *)(ABRecordCopyCompositeName(person)));
78 }else{
79 NSLog(@"点击了取消.");
80 }
81 //关闭模态视图窗口
82 [self dismissViewControllerAnimated:YES completion:nil];
83
84 }
85 #pragma mark - ABUnknownPersonViewController代理方法
86 //保存未知联系人时触发
87 -(void)unknownPersonViewController:(ABUnknownPersonViewController *)unknownCardViewController didResolveToPerson:(ABRecordRef)person{
88 if (person) {
89 NSLog(@"%@ 信息保存成功!",(__bridge NSString *)(ABRecordCopyCompositeName(person)));
90 }
91 [self dismissViewControllerAnimated:YES completion:nil];
92 }
93 //选择一个人员属性后触发,返回值YES表示触发默认行为操作,否则执行代理中自定义的操作
94 -(BOOL)unknownPersonViewController:(ABUnknownPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
95 if (person) {
96 NSLog(@"选择了属性:%i,值:%@.",property,(__bridge NSString *)ABRecordCopyValue(person, property));
97 }
98 return NO;
99 }
100 #pragma mark - ABPersonViewController代理方法
101 //选择一个人员属性后触发,返回值YES表示触发默认行为操作,否则执行代理中自定义的操作
102 -(BOOL)personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
103 if (person) {
104 NSLog(@"选择了属性:%i,值:%@.",property,(__bridge NSString *)ABRecordCopyValue(person, property));
105 }
106 return NO;
107 }
108 #pragma mark - ABPeoplePickerNavigationController代理方法
109 //选择一个联系人后,注意这个代理方法实现后属性选择的方法将不会再调用
110 -(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person{
111 if (person) {
112 NSLog(@"选择了%@.",(__bridge NSString *)(ABRecordCopyCompositeName(person)));
113 }
114 }
115 //选择属性之后,注意如果上面的代理方法实现后此方法不会被调用
116 //-(void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
117 // if (person && property) {
118 // NSLog(@"选择了属性:%i,值:%@.",property,(__bridge NSString *)ABRecordCopyValue(person, property));
119 // }
120 //}
121 //点击取消按钮
122 -(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker{
123 NSLog(@"取消选择.");
124 }
125 @end

运行效果:


注意:为了让大家可以更加清楚的看到几个控制器视图的使用,这里并没有结合前面的UITableViewController来使用,事实上大家结合前面UITableViewController可以做一个完善的通讯录应用。
iOS开发——高级技术&通讯录服务的更多相关文章
- iOS开发——高级技术&通讯录功能的实现
通讯录功能的实现 iOS 提供了对通讯录操作的组建,其中一个是直接操作通讯录,另一个是调用通讯录的 UI 组建.实现方法如下: 添加AddressBook.framework到工程中. 代码实现: 1 ...
- iOS开发——高级技术&蓝牙服务
蓝牙服务 蓝牙 随着蓝牙低功耗技术BLE(Bluetooth Low Energy)的发展,蓝牙技术正在一步步成熟,如今的大部分移动设备都配备有蓝牙4.0,相比之前的蓝牙技术耗电量大大降低.从iOS的 ...
- iOS开发——高级技术&iCloud服务
iCloud服务 iCloud 是苹果提供的云端服务,用户可以将通讯录.备忘录.邮件.照片.音乐.视频等备份到云服务器并在各个苹果设备间直接进行共享而无需关心数据同步问题,甚至 即使你的设备丢失后在一 ...
- iOS开发——高级技术&PassBook服务
PassBook服务 Passbook是苹果推出的一个管理登机牌.会员卡.电影票.优惠券等信息的 工具.Passbook就像一个卡包,用于存放你的购物卡.积分卡.电影票.礼品卡等,而这些票据就是一个“ ...
- iOS开发——高级技术&社交服务
社交服务 Social 现 在很多应用都内置“社交分享”功能,可以将看到的新闻.博客.广告等内容分享到微博.微信.QQ.空间等,其实从iOS6.0开始苹果官方就内置了 Social.framework ...
- iOS开发——高级技术&GameCenter服务
GameCenter服务 Game Center是由苹果发布的在线多人游戏社交网络,通过它游戏玩家可以邀请好友进行多人游戏,它也会记录玩家的成绩并在排行榜中展示,同时玩家每经过一定 的阶段会获得不同的 ...
- iOS开发——高级技术&内购服务
内购服务 大家都知道做iOS开发本身的收入有三种来源:出售应用.内购和广告.国内用户通常很少直接 购买应用,因此对于开发者而言(特别是个人开发者),内购和广告收入就成了主要的收入来源.内购营销模式,通 ...
- iOS开发——高级技术OC篇&运行时(Runtime)机制
运行时(Runtime)机制 本文将会以笔者个人的小小研究为例总结一下关于iOS开发中运行时的使用和常用方法的介绍,关于跟多运行时相关技术请查看笔者之前写的运行时高级用法及相关语法或者查看响应官方文档 ...
- iOS开发——高级技术精选OC篇&Runtime之字典转模型实战
Runtime之字典转模型实战 如果您还不知道什么是runtime,那么请先看看这几篇文章: http://www.cnblogs.com/iCocos/p/4734687.html http://w ...
随机推荐
- hdu 2202 最大三角形 (凸包)
最大三角形 Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submi ...
- plupload简易应用 多图片上传显示预览以及删除
<script> var uploader = new plupload.Uploader({ //实例化一个plupload上传对象 browse_button: 'btnBrowse' ...
- [转] 在Linux平台使用mhVTL虚拟化磁带库
原文来自:LIUBINGLIN ---- http://blog.itpub.net/23135684/viewspace-1307626/ <在Linux平台安装mhVTL虚拟化磁带库> ...
- mysql术语解释
数据库(database): 数据表的集合: 数据表 (table):数据的矩阵: 列(column): 相同属性的数据的集合: 行(row): 一个对象的各种属性数据的集合: 冗余():一个字段在多 ...
- 阿里巴巴Json工具-Fastjson讲解
Fastjson是阿里巴巴公司开源的速度最快的Json和对象转换工具,一个Java语言编写的JSON处理器. 1.遵循http://json.org标准,为其官方网站收录的参考实现之一.2.功能qia ...
- List的使用
List<string> AllFilesPath = new List<string>(); ) // get all files path { ; i < files ...
- Mysql 复合键索引性能
数据库的常见的索引一般是单个字段,如果多个字段的组合,那么就组成了复合索引.对于组合索引,如果 对其中一字段做为条件查询,会出现什么情况呢? 一.例子 mysql> show create ta ...
- 50条LINUX命令整理
1. find 基本语法参数如下: find [PATH] [option] [action] # 与时间有关的参数: -mtime n : n为数字,意思为在n天之前的“一天内”被更改过的文件: - ...
- GridView获取当前行
int row = ((GridViewRow)((DropDownList)sender).NamingContainer).RowIndex; //获取GridView里的DropDownList ...
- C++混合编程之idlcpp教程Lua篇(2)
在上一篇 C++混合编程之idlcpp教程(一) 中介绍了 idlcpp 工具的使用.现在对 idlcpp 所带的示例教程进行讲解,这里针对的 Lua 语言的例子.首先看第一个示例程序 LuaTuto ...