通讯录服务
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"