通讯录技术
目标:获取通讯录中的信息.简称AB和CN.
iOS9.0之前:(使用C语言的数据类型)
1. AddressBook
2. AddressBookUI
iOS9.0之后:(使用OC对象来开发)
1. Contact - 没有提供界面,直接操作数据
2. ContactUI - 提供界面
代码:
目标:看的懂,前人写的代码.(了解一下)
- 导入AddressBookUI框架
- ABPerplePickerNavgationController控制器
- 配置代理,注意不能直接设置代理,代理是父类(导航控制器)的代理,他的代理peoplePickerDelegate.
- 写代理方法
已经被废弃了...
// 与UIImagePicker用法类似
// ABPeoplePickerNavigationController 联系人选择器
// 1. 实例化
ABPeoplePickerNavigationController *peoplePicker = [[ABPeoplePickerNavigationController alloc] init];
// 2. 配置
// 配置代理, 通过代理做一些相关的操作
// delegate 是从 UINavigationController 继承过来的
// peoplePicker.delegate = self;
// 注意: 它的代理是peoplePickerDelegate, 而不是delegate
peoplePicker.peoplePickerDelegate = self;
// 3. 弹出来
[self presentViewController:peoplePicker animated:YES completion:nil];
/// 代理方法
/**
选择了某个联系人详情中的具体属性后触发
* 不能实现选中联系人的代理方法, 否则该方法无效
*/
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier
{
// person 选中的联系人的记录
// property 选中的属性的proertyID (哪一种类型)
// identifier 选中的这一类属性的标识 (判断第一个还是第二个...)
/** 获取选中的电话号码 */
// 1. 判断类型, 不同类型的处理不一样
if (property == kABPersonPhoneProperty) {
// 选中的是一个电话号码
ABMultiValueRef multiPhone = ABRecordCopyValue(person, kABPersonPhoneProperty);
// 判断选中的是哪一个电话号码
NSLog(@"%zd", identifier);
CFIndex index = ABMultiValueGetIndexForIdentifier(multiPhone, identifier);
CFStringRef phone = ABMultiValueCopyValueAtIndex(multiPhone, index);
NSString *phoneString = CFBridgingRelease(phone);
NSLog(@"%@", phoneString);
}
}
注意一种类型以Ref结尾,说明是C语言数据类型.
CF:Core Foundtation框架,是不支持ARC的,这就是为什么碰到Creat,Copy就会产生内存泄漏,需要手动释放内存.
重点: Foundation和Core Foundataion 之间的转化
转化方式1:直接转化,对象所有权(谁负责生命周期管理)不会改变,还是C的生命周期.
__bridge
所以需要CFRelease()一下.转化方式2:CFBridgingRelease(),等价于(__bridge_transer id)会转化对象的所有权,由ARC(编译期特性)负责.
OC的重点掌握
- 导入ContactUI框架
- CNContactPickerViewController
- 配置代理.
- 弹出控制器.
代理方法:
- 点击右上角取消按钮
- 选中了联系人
- 联系人具体信息
- 电话号码:多个电话号码,CNLabledValue:类似于字典.
- 选中多个联系人,选中单个的方法就不走了(类似2中的方法)
- 选中联系人属性
4.1. 通用的代理方法,需要判断类型.如果是这个你需要的类型才作出处理.
4.2. 判断选中的类型是否是电话号码.找到相关value,输出电话号码. - 加一个属性,指定只显示的属性display...
代码部分
// 1. 实例化一个联系人选择器
CNContactPickerViewController *picker= [[CNContactPickerViewController alloc] init];
// 2. 配置
picker.delegate = self;
// 3. 弹出来
[self presentViewController:picker animated:YES completion:nil];
/**
选中了某个联系人后触发
@param contact 选中的联系人信息
*/
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact
{
// CNContact : 表示联系人的具体信息
NSLog(@"%@, %@", contact.familyName, contact.givenName);
// CNLabeledValue : 类似于字典, 保存了 mobile : 5555-1212
NSArray <CNLabeledValue *> *phoneNumbers = contact.phoneNumbers;
for (CNLabeledValue *labelValue in phoneNumbers) {
// CNPhoneNumber 表示电话号码
CNPhoneNumber *number = labelValue.value;
NSLog(@"%@, %@", labelValue.label, number.stringValue);
}
}
/**
实现该代理方法, 支持多选, 选中单个联系人的代理方法失效
*/
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContacts:(NSArray<CNContact*> *)contacts
{
for (CNContact *contact in contacts) {
NSLog(@"%@, %@", contact.familyName, contact.givenName);
}
}
/**
在联系人详情界面中选了联系人的某个属性
@param contactProperty 选中的联系的某个属性
*/
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty
{
// CNContactProperty : 表示联系人的某一个属性
// ========== 获取选中的电话号码 ==========
NSLog(@"%@", contactProperty);
// 1. 判断选中的类型是否为电话号码
// CNContactPhoneNumbersKey的内容就是@"phoneNumbers"
if ([contactProperty.key isEqualToString:@"phoneNumbers"]) {
NSLog(@"%@", contactProperty.value);
CNPhoneNumber *number = contactProperty.value;
NSLog(@"%@", number.stringValue);
}
// ========== 获取选中的邮箱 ==========
if ([contactProperty.key isEqualToString:CNContactEmailAddressesKey]) {
// 就是NSString类型
NSLog(@"%@", contactProperty.value);
}
}
目标:获取通讯录中,所有联系人信息.
相关框架:Contacts框架
核心类:CNContactStore.作用:可以检索和保存联系人等信息
思路:
- 获取通讯录信息
1.1. 首先获取授权权限(参照地图)
1.1.1. 获取当前授权状态
1.1.2. 判断授权状态是否做出改变处理
1.1.3. 请求授权. - 遍历通讯录中所有联系人信息.
- 遍历获取电话号码对应的类型.
注意问题:
- 权限问题配置info.plist(产生崩溃)
- 在检索中没有使用fetch.产生崩溃.(没听清,用到时处理一下)
// ========== 通讯录的授权处理 ==========
// 1. 获取当前的授权状态
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
// 2. 判断是否已经做出决定
if (status == CNAuthorizationStatusNotDetermined) {
[self.contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
// 授权状态的结果, 直接通过Block回调
if (error) {
// 相关的错误信息, 在CNError.h文件当中
NSLog(@"%@", error);
return;
}
if (granted == YES) {
NSLog(@"授权成功");
}
}];
}
// ========== 获取通讯录当中联系人电话和姓名 ==========
// 直接遍历通讯录中所有联系人的信息
// CNContactFetchRequest : 联系人信息(如电话, 邮箱, 地址等)的`检索请求`
// 创建了一个检索请求, 要检索的信息包括姓名, 电话
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactPhoneNumbersKey]];
NSError *error = nil;
// 遍历所有的联系人信息, 如果成功返回YES, 每个联系人信息都会执行一次Block
BOOL result = [self.contactStore enumerateContactsWithFetchRequest:request error:&error usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
// CNContact : 检索到的每个联系人的所有信息
// NSLog(@"%@", contact.emailAddresses);
// stop指针能在需要的时候停止遍历
// 获取姓名
NSLog(@"%@, %@", contact.familyName, contact.givenName);
// 获取电话号码
NSArray <CNLabeledValue *> *phonenumbers = contact.phoneNumbers;
for (CNLabeledValue *labeledValue in phonenumbers) {
// 获取到电话号码对应的类型
CNPhoneNumber *number = labeledValue.value;
NSLog(@"%@, %@", labeledValue.label, number.stringValue);
}
}];
// 失败处理
if (result == NO && error) {
NSLog(@"获取所有联系人信息失败: %@", error);
}
了解知识:AddressBook,访问通讯录数据
ABAddressBookRef:通讯录
CFArrayRef:联系人数组