文档章节

iOS框架—使用地址簿

TomatosX
 TomatosX
发布于 2015/06/14 20:04
字数 2270
阅读 1643
收藏 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开发前就应该知道的事(part 2)

英文原文:Things I wish I had known before starting iOS development—Part 2 如果你还没读这篇文章的第一部分,请先读完了再来看第二部分。 那些在学习iOS开发前就应该知道的事(part 1)...

TomatosX
2015/06/12
0
0
Framework7 3.0.0 beta8 发布,全功能 HTML 框架

Framework7 3.0.0 beta8 已发布。更新内容如下: Phenome 将 object rest spread 语法转换为 Vue/React 组件中的 Object.assign 语法 下载地址: framework7-react.tar.gz framework7-vue.t......

达尔文
06/12
0
0
一样的iOS开发程序员为什么有人4k有人40k?

前言 移动开发真正火起来其实就是最近这几年,iOS 开发技术因为发展也就才这么几年,所以值得做的事情还有很多,这就造成了每年苹果的 WWDC 都会推出一堆新的特性和 API。整体上来说,这对业...

原来是泽镜啊
05/16
0
0
再看知名应用背后的第三方开源项目

知名应用程序的设计和技术一直都是开发者需要学习的,同样这些应用所使用的开源框架也是不可忽视的一部分。此前《iOS第三方开源库的吐槽和备忘》中作者ibireme列举了国内多款知名应用所使用的...

hejunbinlan
2015/08/18
0
0
fir.im Weekly - iOS 开发中的 Git 流程

本期 fir.im Weekly 收集了微博上的热转资源,包含 Android、iOS 开发工具、源码等好用的轮子,还有一些 APP 设计的 Tips,希望对你有用。 精仿知乎日报 iOS 端 @我偏笑_NSNirvana花了将近一...

风起云飞fir_im
2015/11/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Mac OS X下Maven的安装与配置

Mac OS X 安装Maven: 下载 Maven, 并解压到某个目录。例如/Users/robbie/apache-maven-3.3.3 打开Terminal,输入以下命令,设置Maven classpath $ vi ~/.bash_profile 添加下列两行代码,之后...

TonyStarkSir
今天
3
0
关于编程,你的练习是不是有效的?

最近由于工作及Solution项目的影响,我在重新学习DDD和领域建模的一些知识。然后,我突然就想到了这个问题,以及我是怎么做的? 对于我来说,提升技能的项目会有四种: 纯兴趣驱动的项目。即...

问题终结者
今天
4
0
打开eclipse出现an error has occurred see the log file

解决方法: 1,打开eclipse安装目录下的eclipse.ini文件; 2,打开的文本文件最后添加一行 --add-modules=ALL-SYSTEM 3,保存重新打开Eclipse。...

任梁荣
昨天
4
0
搞定Northwind示例数据库,无论哪个版本的SQLServer都受用

Northwind数据库 从这里可以找到突破口: http://social.msdn.microsoft.com/Forums/zh-CN/Vsexpressvb/thread/8490a1c6-9018-40c9-aafb-df9f79d29cde 下面是MSDN: http://msdn2.microsoft......

QQZZFT
昨天
1
0
mysql主从同步,安装配置操作

准备 两台mysql服务,我这里准备了如下: 主库:192.168.176.128 从库:192.168.176.131 如何在Linux上安装mysql服务,请看https://blog.csdn.net/qq_18860653/article/details/80250499 操作...

小致dad
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部