文档章节

iOS框架—使用地址簿

TomatosX
 TomatosX
发布于 2015/06/14 20:04
字数 2270
阅读 1629
收藏 5
点赞 0
评论 0

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

当开发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
fir.im Weekly - iOS 开发中的 Git 流程

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

风起云飞fir_im
2015/11/03
0
0
转:一套代码iOS、Android两端运行,Google Flutter意味着什么?

原文:https://www.toutiao.com/a6569388465538990600/?ttfrom=weixin&utmcampaign=clientshare×tamp=1529580533&app=newsarticle&utmsource=weixin&iid=35476649324&utmmedium=toutiao......

鸿蒙无上至尊
06/22
0
0
那些在学习iOS开发前就应该知道的事(part 1)

英文原文:Things I wish I had known before starting iOS development—Part 1 设计师设计出来了一个不错的引导界面,然而当我看到设计稿的时候,我们的app也没几天就要上线了。这个界面模...

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

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

原来是泽镜啊
05/16
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第三方开源库的吐槽和备忘》中作者ibireme列举了国内多款知名应用所使用的...

hejunbinlan
2015/08/18
0
0
一套代码iOS、Android两端运行,Google Flutter意味着什么?

作者 | 屠敏 一套代码可支持 Android 和 iOS 双端运行,你 Get 了吗? 它就是 Flutter。其目标是为了解决移动中的两个重要问题:一是实现原生应用的性能和与平台的集成,二是提供一个多平台,...

终端研发部
06/22
0
0
苹果账号的分类以及注册免费苹果账号

苹果账号的分类以及注册免费苹果账号 苹果账号的分类 在苹果公司注册苹果账号,就可以成为开发成员。开发成员一共可以分为四种,如表1-2所示。 表1-2 苹果账号的成员 以下是注册一个免费的苹...

大学霸
2015/01/04
0
0
(转)直接拿来用!最火的iOS开源项目(二)

“每一次的改变总意味着新的开始。”这句话用在iOS上可谓是再合适不过的了。GitHub上的iOS开源项目数不胜数,iOS每一次的改变,总会引发iOS开源项目的演变,从iOS 1.x到如今的iOS 7,有的项目...

孙启超
2013/06/21
0
1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

shell中的函数、shell中的数组、告警系统需求分析

shell中的函数 格式: 格式: function f_name() { command } 函数必须要放在最前面 示例1(用来打印参数) 示例2(用于定义加法) 示例3(用于显示IP) shell中的数组 shell中的数组1 定义数...

Zhouliang6
55分钟前
2
0
用 Scikit-Learn 和 Pandas 学习线性回归

      对于想深入了解线性回归的童鞋,这里给出一个完整的例子,详细学完这个例子,对用scikit-learn来运行线性回归,评估模型不会有什么问题了。 1. 获取数据,定义问题     没有...

wangxuwei
今天
1
0
MAC安装MAVEN

一:下载maven压缩包(Zip或tar可选),解压压缩包 二:打开终端输入:vim ~/.bash_profile(如果找不到该文件新建一个:touch ./bash_profile) 三:输入i 四:输入maven环境变量配置 MAVEN_HO...

WALK_MAN
今天
0
0
33.iptables备份与恢复 firewalld的9个zone以及操作 service的操作

10.19 iptables规则备份和恢复 10.20 firewalld的9个zone 10.21 firewalld关于zone的操作 10.22 firewalld关于service的操作 10.19 iptables规则备份和恢复: ~1. 保存和备份iptables规则 ~2...

王鑫linux
今天
2
0
大数据教程(2.11):keeperalived+nginx高可用集群搭建教程

上一章节博主为大家介绍了目前大型互联网项目的系统架构体系,相信大家应该注意到其中很重要的一块知识nginx技术,在本节博主将为大家分享nginx的相关技术以及配置过程。 一、nginx相关概念 ...

em_aaron
今天
1
0
Apache Directory Studio连接Weblogic内置LDAP

OBIEE默认使用Weblogic内置LDAP管理用户及组。 要整理已存在的用户及组,此前办法是导出安全数据,文本编辑器打开认证文件,使用正则表达式获取用户及组的信息。 后来想到直接用Apache Dire...

wffger
今天
2
0
HFS

FS,它是一种上传文件的软件。 专为个人用户所设计的 HTTP 档案系统 - Http File Server,如果您觉得架设 FTP Server 太麻烦,那么这个软件可以提供您更方便的档案传输系统,下载后无须安装,...

garkey
今天
1
0
Java IO类库之BufferedInputStream

一、BufferedInputStream介绍 /** * A <code>BufferedInputStream</code> adds * functionality to another input stream-namely, * the ability to buffer the input and to * sup......

老韭菜
今天
0
0
STM 32 窗口看门狗

http://bbs.elecfans.com/jishu_805708_1_1.html https://blog.csdn.net/a1985831055/article/details/77404131...

whoisliang
昨天
1
0
Dubbo解析(六)-服务调用

当dubbo消费方和提供方都发布和引用完成后,第四步就是消费方调用提供方。 还是以dubbo的DemoService举例 -- 提供方<dubbo:application name="demo-provider"/><dubbo:registry address="z...

青离
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部