读取通信录中的联系人一般的过程是先查找联系人记录,然后再访问记录的属性,属性又可以分为单值属性和多值属性。通过下面例子介绍联系人的查询,以及单值属性和多值属性的访问,还有读取联系人中的图片数据。
本案例是从iOS设备上读取通讯录中的联系人,并将其显示在一个表视图中,可以进行查询,点击联系人进入详细信息画面。访问通讯录的应用必须要做的两件事情:
1、添加AddressBook和AddressBookUI框架
为工程添加AddressBook.framework和AddressBookUI.framework
2、引入头文件
在需要访问通讯录类的头文件中引入下面头文件:
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>
查询联系人记录
在从通信录数据库查询联系人数据是无法使用SQL语句,只能通过ABAddressBookCopyArrayOfAllPeople和ABAddressBookCopyPeopleWithName函数获得,它们的定义如下:
CFArrayRef ABAddressBookCopyArrayOfAllPeople ( ABAddressBookRef addressBook ); CFArrayRef ABAddressBookCopyPeopleWithName ( ABAddressBookRef addressBook, CFStringRef name );
ABAddressBookCopyArrayOfAllPeople函数是查询所有的联系人数据。 ABAddressBookCopyPeopleWithName函数是通过人名查询通讯录中的联系人,其中的name参数就是查询的前缀关键字。两个函 数中都有addressBook参数,它是我们要查询的通讯录对象,其创建使用ABAddressBookCreateWithOptions函数(在 iOS6之前是ABAddressBookCreate函数),它的定义:
ABAddressBookRef ABAddressBookCreateWithOptions ( CFDictionaryRef options, CFErrorRef* error );
options参数是保留参数,目前没有采用,使用时候可以传递NULL值。error是错误对象,包含错误信息。
下面是我们代码中有关系查询的部分,先看一下ViewController.h:
#import <UIKit/UIKit.h> #import <AddressBook/AddressBook.h> #import ”DetailViewController.h” @interface ViewController : UITableViewController <UISearchBarDelegate, UISearchDisplayDelegate> @property (nonatomic, strong) NSArray *listContacts; - (void)filterContentForSearchText:(NSString*)searchText; @end
属性listContacts是装载联系人记录数组集合,filterContentForSearchText:方法是用来过滤联系人信息的方法,也就是查询方法。
ViewController.m中的viewDidLoad方法:
- (void)viewDidLoad { [super viewDidLoad]; CFErrorRef error = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error); ① ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { ② if (granted) { //查询所有 [self filterContentForSearchText:@""]; ③ } }); CFRelease(addressBook); ④ }
在viewDidLoad方法中首先在第①行代码处使用 ABAddressBookCreateWithOptions函数创建addressBook对象,然后在第②行又调用了函数 ABAddressBookRequestAccessWithCompletion,这个函数用于向用户请求访问通讯录数据库,如果是第一次访问,则会 弹出一个用户授权对话框,如果用户授权可以访问则会调用下面的代码块。
^(bool granted, CFErrorRef error) { if (granted) { } });
由于请求和代码块的回调都是异步的,你会发现表视图画面先出现,然后过一会儿才有查询出来的结果。在iOS6之后这个请求过程必须有的,否则无法访问通讯录数据库。
ViewController.m中的filterContentForSearchText:查询方法:
- (void)filterContentForSearchText:(NSString*)searchText { //如果没有授权则退出 if (ABAddressBookGetAuthorizationStatus() != kABAuthorizationStatusAuthorized) { return ; } CFErrorRef error = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error); if([searchText length]==0) { //查询所有 self.listContacts = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook)); } else { //条件查询 CFStringRef cfSearchText = (CFStringRef)CFBridgingRetain(searchText); self.listContacts = CFBridgingRelease(ABAddressBookCopyPeopleWithName(addressBook, cfSearchText)); CFRelease(cfSearchText); } [self.tableView reloadData]; CFRelease(addressBook); }
在该方法中实现查询,ABAddressBookGetAuthorizationStatus()函数返回应用的 授权状态,其中kABAuthorizationStatusAuthorized常量代表用户已经授权,在没有授权情况下该方法不进行任何处理。 ABAddressBookCopyArrayOfAllPeople函数是查询所有数 据,ABAddressBookCopyPeopleWithName函数是根据条件查询,返回值是CFArrayRef类型,不能直接赋值给 listContacts(NSArray*类型)属性,处理方式一般如下两种:
self.listContacts = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook) ;
或
self.listContacts = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook));
(__bridge NSArray *) 方式不会转让对象所有权,只是简单强制转化。CFBridgingRelease函数实现的是Core Foundation类型到Foundation 类型转化并把对象所有权转让ARC(自动管理引用计数),因此不需要释放属性listContacts对应的成员变量。类似还有 CFBridgingRetain函数,实现的是Foundation类型到Core Foundation类型转化, 并把对象所有权转让调用者,因此 需要释放这个对象,代码如下:
CFStringRef cfSearchText = (CFStringRef)CFBridgingRetain(searchText); self.listContacts = CFBridgingRelease(ABAddressBookCopyPeopleWithName(addressBook, cfSearchText)); CFRelease(cfSearchText);
最后在第④行调用CFRelease(addressBook)函 数释放addressBook对象,Core Foundation框架中的数据类型内存管理是不受ARC管理的,但是与Foundation框架的 MRC管理类似,需要手动释放,CFRelease函数就是相当于Foundation框架中的release(或autorelease)方法。
ViewController.m中的SearchBar查询相关方法:
#pragma mark –UISearchBarDelegate 协议方法
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { //查询所有 [self filterContentForSearchText:@""]; } #pragma mark - UISearchDisplayController Delegate Methods //当文本内容发生改变时候,向表视图数据源发出重新加载消息 - (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString { [self filterContentForSearchText:searchString]; //YES情况下表视图可以重新加载 return YES; }
读取单值属性
在一条联系人记录中,有很多属性,这些属性有单值属性和多值属性,单值属性是只有一个值的属性,如:姓氏、名字等,它们是由下面常量定义的:
kABPersonFirstNameProperty,名字
kABPersonLastNameProperty,姓氏
kABPersonMiddleNameProperty,中间名
kABPersonPrefixProperty,前缀
kABPersonSuffixProperty,后缀
kABPersonNicknameProperty,昵称
kABPersonFirstNamePhoneticProperty,名字汉语拼音或音标
kABPersonLastNamePhoneticProperty,姓氏汉语拼音或音标
q kABPersonMiddleNamePhoneticProperty,中间名汉语拼音或音标
kABPersonOrganizationProperty,组织名
kABPersonJobTitleProperty,头衔
kABPersonDepartmentProperty,部门
kABPersonNoteProperty,备注
读取记录属性函数是ABRecordCopyValue,ABRecordCopyValue函数的定义如下:
CFTypeRef ABRecordCopyValue ( ABRecordRef record, ABPropertyID property );
ABRecordRef参数是记录对象,ABPropertyID是属性ID,就是上面的常量 kABPersonFirstNameProperty等。返回值类型是CFTypeRef,它是Core Foundation类型的“泛型”,可以代 表任何的Core Foundation类型。
ViewController.m中的tableView:cellForRowAtIndexPath:方法,主要实现了访问单值属性:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @”Cell”; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } ABRecordRef thisPerson = CFBridgingRetain([self.listContacts objectAtIndex:[indexPath row]]); ① NSString *firstName = CFBridgingRelease(ABRecordCopyValue(thisPerson, kABPersonFirstNameProperty)); ② firstName = firstName != nil?firstName:@”"; NSString *lastName = CFBridgingRelease(ABRecordCopyValue(thisPerson, kABPersonLastNameProperty)); ③ lastName = lastName != nil?lastName:@”"; cell.textLabel.text = [NSString stringWithFormat:@"%@ %@",firstName,lastName]; CFRelease(thisPerson); return cell; }
第①行 ABRecordRef thisPerson = CFBridgingRetain([self.listContacts objectAtIndex: [indexPath row]])语句是从NSArray*集合中取出一个元素,并且转化为Core Foundation类型的 ABRecordRef类型。 CFBridgingRelease(ABRecordCopyValue(thisPerson, kABPersonFirstNameProperty)) 语句是将名字属性取出来,转化为NSString*类型。最后CFRelease(thisPerson)是释放ABRecordRef对象。
此外,为了把选中的联系人传递给详细画面,我们需要获得选中记录的ID,然后把ID传递到详细画面,这个过程处理是在ViewController.m中的 prepareForSegue:方法完成的:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([[segue identifier] isEqualToString:@”showDetail”]) { NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; ABRecordRef thisPerson = CFBridgingRetain([self.listContacts objectAtIndex:[indexPath row]]); DetailViewController *detailViewController = [segue destinationViewController]; ABRecordID personID = ABRecordGetRecordID(thisPerson); ① NSNumber *personIDAsNumber = [NSNumber numberWithInt:personID]; ② detailViewController.personIDAsNumber = personIDAsNumber; ③ CFRelease(thisPerson); ④ } }
其中第①行代码调用函数ABRecordGetRecordID是获取选中记录的ID,其中ID为 ABRecordID类型。为了传递这个ID给DetailViewController视图控制器,DetailViewController视图控制 器定义了personIDAsNumber属性,在第③行将ID给personIDAsNumber属性。DetailViewController.h代码如下:
#import <UIKit/UIKit.h>
#import <AddressBook/AddressBook.h>
@interface DetailViewController : UITableViewController
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UILabel *lblName;
@property (weak, nonatomic) IBOutlet UILabel *lblMobile;
@property (weak, nonatomic) IBOutlet UILabel *lblIPhone;
@property (weak, nonatomic) IBOutlet UILabel *lblWorkEmail;
@property (weak, nonatomic) IBOutlet UILabel *lblHomeEmail;
@property (strong, nonatomic) NSNumber* personIDAsNumber;
@end
personIDAsNumber属性为NSNumber*类型。
读取多值属性
多值属性是包含多个值的集合类型,如:电话号码、Email、URL等,它们主要是由下面常量定义的:
kABPersonPhoneProperty,电话号码属性,kABMultiStringPropertyType类型多值属性;
kABPersonEmailProperty,Email属性,kABMultiStringPropertyType类型多值属性;
kABPersonURLProperty,URL属性,kABMultiStringPropertyType类型多值属性;
kABPersonRelatedNamesProperty,亲属关系人属性,kABMultiStringPropertyType类型多值属性;
kABPersonAddressProperty,地址属性,kABMultiDictionaryPropertyType类型多值属性;
kABPersonInstantMessageProperty,即时聊天属性,kABMultiDictionaryPropertyType类型多值属性;
kABPersonSocialProfileProperty,社交账号属性,kABMultiDictionaryPropertyType类型多值属性;
在多值属性中包含了label(标签)、value(值)和ID等部分,其中标签和值都是可以重复的,而ID是不能重复的
多 值属性访问方式与单值属性访问类似都使用ABRecordCopyValue函数。不同的是多值属性访问返回值是ABMultiValueRef,然后要 使用ABMultiValueCopyArrayOfAllValues函数从ABMultiValueRef对象中获取数组CFArrayRef集合。 ABMultiValueCopyArrayOfAllValues函数的定义如下:
CFArrayRef ABMultiValueCopyArrayOfAllValues ( ABMultiValueRef multiValue ); ABMultiValueCopyLabelAtIndex函数可以从ABMultiValueRef对象中返回标签,其定义如下: CFStringRef ABMultiValueCopyLabelAtIndex ( ABMultiValueRef multiValue, CFIndex index );
参数multiValue是ABMultiValueRef对象,index是查找标签的索引。
ABMultiValueGetIdentifierAtIndex函数可以从ABMultiValueRef对象中返回ID,其定义如下:
ABMultiValueIdentifier ABMultiValueGetIdentifierAtIndex ( ABMultiValueRef multiValue, CFIndex index ); 在DetailViewController.m文件viewDidLoad方法中取得Email多值属性,其代码如下: ABMultiValueRef emailsProperty = ABRecordCopyValue(person, kABPersonEmailProperty); NSArray* emailsArray = CFBridgingRelease(ABMultiValueCopyArrayOfAllValues(emailsProperty)); for(int index = 0; index< [emailsArray count]; index++){ NSString *email = [emailsArray objectAtIndex:index]; NSString *emailLabel = CFBridgingRelease(ABMultiValueCopyLabelAtIndex(emailsProperty, index)); if ([emailLabel isEqualToString:(NSString*)kABWorkLabel]) { [self.lblWorkEmail setText:email]; } else if ([emailLabel isEqualToString:(NSString*)kABHomeLabel]) { [self.lblHomeEmail setText:email]; } else { NSLog(@”%@: %@”, @”其它Email”, email); } } CFRelease(emailsProperty);
其中 ABMultiValueCopyArrayOfAllValues(emailsProperty))语句是从emailsProperty属性中取出 数组集合。kABWorkLabel和kABHomeLabel都是Email多值属性的标签。kABWorkLabel是工作Email标签和 kABHomeLabel是家庭Email标签,另外还有kABOtherLabel,它是Email标签。最后emailsProperty需要释放。
DetailViewController.m中的viewDidLoad方法中取得电话号码多值属性代码如下:
ABMultiValueRef phoneNumberProperty = ABRecordCopyValue(person, kABPersonPhoneProperty); NSArray* phoneNumberArray = CFBridgingRelease(ABMultiValueCopyArrayOfAllValues(phoneNumberProperty)); for(int index = 0; index< [phoneNumberArray count]; index++){ NSString *phoneNumber = [phoneNumberArray objectAtIndex:index]; NSString *phoneNumberLabel = CFBridgingRelease(ABMultiValueCopyLabelAtIndex(phoneNumberProperty, index)); if ([phoneNumberLabel isEqualToString:(NSString*)kABPersonPhoneMobileLabel]) { [self.lblMobile setText:phoneNumber]; } else if ([phoneNumberLabel isEqualToString:(NSString*)kABPersonPhoneIPhoneLabel]) { [self.lblIPhone setText:phoneNumber]; } else { NSLog(@”%@: %@”, @”其它电话”, phoneNumber); } } CFRelease(phoneNumberProperty);
kABPersonPhoneMobileLabel 和kABPersonPhoneIPhoneLabel都是电话号码属性的标签。kABPersonPhoneMobileLabel是移动电话号码标 签,kABPersonPhoneIPhoneLabel是iPhone电话号码标签。此外还有:
kABPersonPhoneMainLabel,主要电话号码标签;
kABPersonPhoneHomeFAXLabel,家庭传真电话号码标签;
kABPersonPhoneWorkFAXLabel,工作传真电话号码标签;
kABPersonPhonePagerLabel,寻呼机号码标签。
读取图片属性
通讯录中的联系人可以有一个图片,读取联系人图片的相关函数有ABPersonCopyImageData和ABPersonHasImageData等。ABPersonCopyImageData可以读取联系人图片函数,它的定义如下:
CFDataRef ABPersonCopyImageData ( ABRecordRef person );
它的返回类型是CFDataRef,与之对应的Foundation框架类型是NSData*。ABPersonHasImageData函数用于判断联系人是否有图片,它的定义如下:
bool ABPersonHasImageData ( ABRecordRef person ); DetailViewController.m中的viewDidLoad方法中取得联系人图片代码如下: if (ABPersonHasImageData(person)) { NSData *photoData = CFBridgingRelease(ABPersonCopyImageData(person)); if(photoData){ [self.imageView setImage:[UIImage imageWithData:photoData]]; } }
ABPersonCopyImageData取出的是CFDataRef类型,将其转化为NSData*,再使用UIImage的构造方法imageWithData:构建UIImage对象,然后再把UIImage对象赋值给imageView图片控件。
相关推荐
链接: https://pan.baidu.com/s/1pKMhA4b 密码: pgvd
NULL 博文链接:https://stephen830.iteye.com/blog/2248653
有的时候我们需要读取手机里面的联系人,有的时候我们需要向手机里面写入新的联系人,所以我们就用到了这个demo,这个demo适用iOS9.0之前,但是如果在开发中把适配手机系统调到iOS9.0之前,这个demo还是可以在iOS9.0...
ios 读取通讯录 支持ios6.0 可以获得通讯录中任何信息,demo中主要显示了姓名 和 手机号,其他字段 放在最后的注释中了
传智播客iOS6免费公开课程-实现录音与播放
一款能够读取手机联系人的Demo,解决项目中需要手机中联系人电话号码的需求. 开发者的你,值得拥有!
读取通讯录联系人头像,姓名等信息(号码,首字母,姓名拼音),并按照姓名首字母顺序排序。切出Demo更改联系人信息,切回后同步更新。
ios中获取手机通讯录, 然后以表格的形式显示出来
简单的通讯录读取并排序。预留了获取姓名拼音,以便后期增加搜索功能
项目中有一个功能需要读取通讯录中联系人的手机。在iOS8以前都是可用的,主要使用如下三个代理方法来实现 - (void) peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)...
源码BeautyAddressBook,读取通讯录数据并进行美化 按照名字生成各种颜色的头像 和索引条的创建,里面封装有读取通讯录和字母排序,头像生成 等。
源码适用于:金融业务型公司(当你和客人达成资金担保合作协议,在抄录其50个备用联系人的时候,直接进行读取,省去了一系列烦繁人工。) 流程:客户下载APP注册登录 – 弹出询问客户是否同意读取通讯录(同意后点...
源码适用于:金融业务型公司(当你和客人达成资金担保合作协议,在抄录其50个备用联系人的时候,直接进行读取,省去了一系列烦繁人工。) 流程:客户下载APP注册登录 – 弹出 询问客户是否同意读取通讯录(同意后点...
接下来介绍了如何使用该框架将联系人信息写入数据库,具体包括联系人的创建、修改和删除;最后介绍了如何使用AddressBook高级API实现选择联系人、显示和修改联系人以及创建联系人的操作。 第二部分网络篇,介绍了...
PPGetAddressBook对AddressBook框架(iOS9之前)和Contacts框架(iOS9之后)做了对应的封装处理; 支持获取按联系人姓名首字拼音A~Z排序(重点:已经对姓名的第二个字做了处理,排序更准确!);
主要介绍了IOS中获取本地通讯录联系人以及汉字首字母排序的相关资料,需要的朋友可以参考下
有了这个插件,Flutter应用程序可以要求其用户从他/她的通讯录中选择一个联系人。 与联系人关联的信息将返回到应用程序。 该插件使用操作系统的本机UI来选择联系人,并且不需要用户的任何特殊权限。 当前,该插件...
该源码实现一款实现可以读取本地通讯录联系人信息功能,而且还可以支持同时选择多个联系人个功能,是一个不错的ios学习的例子,喜欢的朋友可以下载学习看看,。