文档章节

iOS框架—使用地址簿

TomatosX
 TomatosX
发布于 2015/06/14 20:04
字数 2270
阅读 1668
收藏 5

一、为何支持地址簿很重要:

当开发iOS软件的时候,就与用户的移动生活建立了联系。用户走到哪里都带着移动设备,可以说移动设备与用户的个人生活(从日历到个人相册)休戚相关。在这种移动生活中,通讯录占据着重要的位置。应用可以使用联系人数据库确定用户是否有朋友注册了相关服务:分析联系人的电子邮件地址或电话号码,并将联系人自动添加为好友。应用还可以使用联系人列表自动填写邮件地址或电话号码,或让用户通过蓝牙与朋友分享联系人信息。应用需要访问用户通讯录的原因不胜枚举。

注意:

除非有充分的理由,否则不要访问联系人数据库,这很重要,因为没有什么比泄露隐私更能让用户毅然决然地放弃使用您的应用了。

二、使用地址簿

想要使用地址簿框架,需要先将两个有关地址薄的框架导入到项目中:AddressBookUI.framework和AddressBook.framework。其中前者提供了选择、编辑和显示联系人的图形用户界面,而后者是让您能够与联系人数据交互。然后在相关的类中导入头文件,如下所示:

#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>
首先,我在项目中创建了两个类的属性:addressBook和addressBookEntryArray
@property (nonatomic, assign) ABAddressBookRef addressBook;
@property (nonatomic, strong) NSMutableArray *addressBookEntryArray;

addressBookEntryArray是用来存储获取到的系统中的地址薄条目数组。

注意:

将地址薄复制到内存的开销极高,因此应最大限度地减少这种操作的次数。
在使用地址簿的时候,我们应该获取访问手机中地址薄的权限:
//申请访问权限
ABAddressBookRequestAccessWithCompletion(_addressBook, ^(bool greanted, CFErrorRef error) {

    //greanted为YES是表示用户允许,否则为不允许
    if (!greanted) {
        NSLog(@"未取得权限");
    }
});
接下来,创建一个地址薄的引用:
CFErrorRef error = NULL;

//创建通讯簿的引用
_addressBook = ABAddressBookCreateWithOptions(nil, &error);
在创建地址薄引用的时候现在最好用ABAddressBookCreateWithOptions这个方法,原来的 ABAddressBookCreate已经作废。

AB_EXTERN ABAddressBookRef ABAddressBookCreateWithOptions(CFDictionaryRef options, CFErrorRef* error) __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_6_0);

AB_EXTERN ABAddressBookRef ABAddressBookCreate(void) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_NA,__MAC_NA,__IPHONE_2_0,__IPHONE_6_0);
由上面的代码可以看出, ABAddressBookCreate支持的版本是iOS 2.0 到 iOS 6.0,在开发iOS 6.0 之后系统的时候应该使用 ABAddressBookCreateWithOptions去创建地址薄的引用。

_addressBookEntryArray = (__bridge NSMutableArray *)ABAddressBookCopyArrayOfAllPeople(_addressBook);

创建了地址薄的引用后,就要将手机地址薄中的联系人拷贝到数组addressBookEntryArray中,这里,我拷贝了所有联系人的信息,其他的拷贝方式请自行查看API文档。在获取所有联系人之前需要考虑到地址薄为空的情形,这种情况下给用户一个良好的提示,让用户知道APP没有出错崩溃,这里我用了一个alert弹窗来简单的显示提示信息。

if(ABAddressBookGetPersonCount(_addressBook) == 0) {
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"联系人为空"
                                                        message:@""
                                                       delegate:nil
                                              cancelButtonTitle:@"确定"
                                              otherButtonTitles: nil];
    [alertView show];
}
在读到地址薄中联系人信息后,这里将获得的数据展示在了一个tableviewcontroller中。

三、从地址簿中读取数据

读入到addressBookEntryArray数组中的每一个条目都是一个ABRecordRef,单值数据可以用方法ABRecordCopyValue方法读取:

ABRecordRef record = (__bridge ABRecordRef)([_addressBookEntryArray objectAtIndex:indexPath.row]);
CFStringRef firstName = ABRecordCopyValue(record, kABPersonFirstNameProperty);
CFStringRef lastName = ABRecordCopyValue(record, kABPersonLastNameProperty);
这里获取了联系人中的firstName和lastName。

ABRecordRef的所有单值属性如下表所示:

属性名 描述
kABPersonFirstNameProperty
kABPersonLastNameProperty
kABPersonMiddleNameProperty 中间名或所写
kABPersonPrefixProperty
姓名前缀(Mr.、Ms.、Dr.)
kABPersonSuffixProperty
姓名后缀(MD、Jr、Sr.)
kABPersonNicknameProperty
别名
kABPersonFirstNamePhoneticProperty
名字的读音
kABPersonLastNamePhoneticProperty
姓的读音
kABPersonMiddleNamePhoneticProperty
中间名读音
kABPersonOrganizationProperty
公司或组织
kABPersonJobTitleProperty
职务
kABPersonDepartmentProperty
部门
kABPersonEmailProperty
邮箱地址
kABPersonBirthdayProperty
CFDate格式的生日,可自由桥接到NSDate
kABPersonNoteProperty
备注
kABPersonCreationDateProperty
CFDate格式的创建日期
kABPersonModificationDateProperty
CFDate格式的最后修改日期

四、从地址薄读取多值数据

当从地址薄中读取多值数据,例如:电话号码、电子邮件地址和街道地址这些数据时,需要用到ABMultiValueRef。这里展示了如何操作地址薄中的地址(地址是一个比较特殊的多值数据,因为取出来的是一个字典类型的数据):

//  通讯录地址的使用
ABMultiValueRef addressMulti = ABRecordCopyValue(record, kABPersonAddressProperty);
NSString *address = nil;
NSString *street = nil;
NSString *city = nil;
NSString *state = nil;
NSString *zip = nil;
if (ABMultiValueGetCount(addressMulti) > 0) {
    NSDictionary *addressDictionary = (__bridge NSDictionary *)(ABMultiValueCopyValueAtIndex(addressMulti, 0));
    street = [addressDictionary objectForKey:(NSString *)kABPersonAddressStreetKey];
    city = [addressDictionary objectForKey:(NSString *)kABPersonAddressCityKey];
    state = [addressDictionary objectForKey:(NSString *)kABPersonAddressStateKey];
    zip = [addressDictionary objectForKey:(NSString *)kABPersonAddressZIPKey];
}

address = [NSString stringWithFormat: @"%@ %@ %@ %@", street, city, state, zip];
从API中得知,地址是一个字典类型的值。首先将地址取出,然后在转换成字典,用API中对应的Key去获得对应的数据。

地址的组成部分由下表所示:

属性 描述
kABPersonAddressStreetKey
街道名和门牌号(包括房间号)
kABPersonAddressCityKey
城市名
kABPersonAddressStateKey
两字符州名或完整的州名
kABPersonAddressZIPKey
邮政编码(5位或者9位数字)
kABPersonAddressCountryKey
完整的国家名
kABPersonAddressCountryCodeKey
两字符国别码

五、地址标签的使用

在通过多值获取到电话号码后,使用的是电话号码的索引号。虽然电话号码索引对开发人员很有用,但是对用户来说毫无意义,因此这里使用地址标签获取到联系人使用的标签。要获取多值引用的标签,首先需要调用ABMultiValueCopyLabelAtIndex。调用这个函数时,使用的参数与获取多值对象的值时相同。这个函数返回一个未经本地化的字符串如:_$!<Mobile>!$_。虽然这个字符串比索引号有用的多,但还是不太合适显示给用户。为获得用户能看明白的字符串,需要将返回的标签进行本地化。为此,可调用ABAddressBookCopyLocalizedLabel,并将刚返回的CFStringRef作为参数。代码中我获取了电话号码的标签,并输出到后台:

//  读取多个值的方法
ABMultiValueRef phoneNumbers = ABRecordCopyValue(record, kABPersonPhoneProperty);

if (ABMultiValueGetCount(phoneNumbers) > 0) {
    for (int i = 0; i < ABMultiValueGetCount(phoneNumbers); i++) {
//    第二个参数是获取电话号码的类型,例如:手机,家庭电话等(地址簿标签)
        NSLog(@"%@ [%@]", ABMultiValueCopyValueAtIndex(phoneNumbers, i), ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(phoneNumbers, i)));
    }
}

六、联系人选择器

联系人选择器创建一个像系统内置的地址薄中的联系人选择器类似的一个界面。首先这个类需要遵守协议ABPeoplePickerNavigationControllerDelegate,然后使用如下的代码创建一个选择控制器。

ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
[self presentViewController:picker animated:YES completion:nil];

选择器创建完成后,这里有三个委托方法,在用户与联系人选择器交互时做出相应。第一个方法是对用户“取消”按钮做出响应:

- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker {
    
    [self dismissViewControllerAnimated:YES completion:nil];
}
第二个委托方法是告诉联系人选择器,您不想让用户选择联系人的具体属性,即用户无法通过联系人选择器查看到联系人的详细信息。当用户选择一个联系人后,联系人选择器就会自动dismiss掉。
// 此方法选择联系人后,不能跳转到详细页面,即不能读取详细信息
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person {

    NSLog(@"You have selected: %@", ABRecordCopyValue(person, kABPersonFirstNameProperty));
}
第三个委托方法实现后,用户可以查看联系人的详细信息。
// 可以获取联系人的详细信息
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier {
    
    NSLog(@"Person: %@, Property: %i, Identifier: %i", person, property, identifier);
}

这里我们还可以定制联系人选择器进入详细页面后所能访问的内容,在创建联系人选择器后,加入下面的代码用户进入详细页面后只能查看联系人的电话号码:

picker.displayedProperties = [NSArray arrayWithObject: [NSNumber numberWithInt:kABPersonPhoneProperty]];

六、使用ABPersonViewController编辑和查看联系人

大多数的情况下,都使用内置的地址薄用户界面来显示或编辑联系人。在此代码中,将联系人信息显示在了一个tableview中,选中cell后将跳转到一个ABPersonViewController页面进行联系人详细信息的查看。

ABPersonViewController *personViewController = [[ABPersonViewController alloc] init];
ABRecordRef record = (__bridge ABRecordRef)([_addressBookEntryArray objectAtIndex:indexPath.row]);
personViewController.personViewDelegate = self;
personViewController.displayedPerson = record;
personViewController.allowsEditing = YES;
personViewController.allowsActions = NO;
[self.navigationController pushViewController:personViewController animated:YES];

这里的allowsEditing属性,是设置进入详细页面后,是否能够编辑联系人信息。

七、使用ABNewPersonViewController新建联系人

ABNewPersonViewController *newPersonController = [[ABNewPersonViewController alloc] init];
newPersonController.newPersonViewDelegate = self;
[self.navigationController pushViewController:newPersonController animated:YES];

当用户保存联系人时,会调用一个委托方法。在这个方法中,确定返回的联系人对象有效后,会依次调用ABAddressBookAddRecord和ABAddressBookSave将联系人保存到地址薄。

- (void)newPersonViewController:(ABNewPersonViewController *)newPersonView didCompleteWithNewPerson:(ABRecordRef)person {
    if (person) {
        CFErrorRef error = NULL;
        ABAddressBookAddRecord(_addressBook, person, &error);
        ABAddressBookSave(_addressBook, &error);
        if (error != NULL) {
            NSLog(@"An error occurred");
        }
    }
    _addressBookEntryArray = (__bridge NSMutableArray *)ABAddressBookCopyArrayOfAllPeople(_addressBook);
    [self.tableView reloadData];
    [self.navigationController popToRootViewControllerAnimated:YES];
}

© 著作权归作者所有

共有 人打赏支持
TomatosX
粉丝 22
博文 207
码字总数 119547
作品 0
成都
iOS工程师
私信 提问
iOS 5.0.1 又曝出联系人不识别的 BUG

新闻来源:macx 据The Startup Foundry网站作者Paul Hontz报道,在无线升级至iOS 5.0.1之后,他的iPhone 4S就无法识别联系人的姓名了。虽然他已经将所有联系人的信息储存在地址簿里,但是当使...

红薯
2011/11/13
964
3
【书坊赠书福利——第二期】《iOS 8开发指南》

本周是人邮IT书坊赠书的第二期,第一期参与度极高,微信君在此感谢你们的支持,第一期获奖赠书已全部寄出。 本周赠品 本周,微信君给大家推荐@人民邮电出版社-信息技术分社 刚刚上架的新书《...

生气的散人
2014/09/23
371
0
Visual Studio 2017 15.6 Preview 2 发布,增加新功能

Visual Studio 2017 15.6 预览版本 2 发布,这版本更新包括 macOS 环境配置,iOS WiFi 部署,在 Remoting iOS 模拟器中进行实时的 XAML 预览,等等。 自动 macOS 配置 在Windows上使用Visua...

周其
01/11
1K
11
苹果被指放任开发者违规上传用户通讯簿

导语:美国科技博客网站Gizmodo周三发表署名达斯汀·柯蒂斯(Dustin Curtis)的文章称,iOS应用开发者可以随意将用户通讯簿的全部内容上传到他们的服务器,尽管这种做法侵犯了用户隐私,同时也...

红薯
2012/02/09
708
5
OSChina 技术专题之 Swift 苹果全新开发语言

Swift 是苹果新推出的编程语言,专门针对 OS X 和 iOS 的应用开发。Swift 在各个方面优于 Objective-C,也不会有那么多复杂的符号和表达式。同时,Swift 更加快速、便利、高效、安全。除此之...

OSC编辑部
2014/11/10
4.2K
4

没有更多内容

加载失败,请刷新页面

加载更多

URL访问网站的网络传输全过程

打开浏览器,在地址栏输入URL,回车,出现网站内容。这是我们几乎每天都在做的事,那这个过程中到底是什么原理呢?HTTP、TCP、DNS、IP这些耳熟能详的名词都在什么时候起着什么作用呢?在这里...

MrBoyce
3分钟前
0
0
都9102年了,还不会Docker?10分钟带你从入门操作到实战上手

Docker简述 Docker是一种OS虚拟化技术,是一个开源的应用容器引擎。它可以让开发者将应用打包到一个可移植的容器中,并且该容器可以运行在几乎所有linux系统中(Windows10目前也原生支持,W...

公众号_Zack说码
3分钟前
0
0
day175-2018-12-12-英语流利阅读-待学习

日本报纸修改二战“慰安妇”描述,引发众怒 雪梨 2018-12-12 1.今日导读 第二次世界大战期间,日本肆意侵略其他国家,所到之处,无数妇女沦为日本士兵肆意践踏的对象。半个多世纪过去了,面对...

飞鱼说编程
5分钟前
1
0
TiDB 源码阅读系列文章(二十一)基于规则的优化 II

在 TiDB 源码阅读系列文章(七)基于规则的优化 一文中,我们介绍了几种 TiDB 中的逻辑优化规则,包括列剪裁,最大最小消除,投影消除,谓词下推和构建节点属性,本篇将继续介绍更多的优化规...

TiDB
11分钟前
0
0
mysql 时间格式化

DATE_FORMAT

1713716445
17分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部