通讯录技术

通讯录技术

目标:获取通讯录中的信息.简称AB和CN.

iOS9.0之前:(使用C语言的数据类型)
1. AddressBook
2. AddressBookUI
iOS9.0之后:(使用OC对象来开发)
1. Contact - 没有提供界面,直接操作数据
2. ContactUI - 提供界面

代码:

目标:看的懂,前人写的代码.(了解一下)
  1. 导入AddressBookUI框架
  2. ABPerplePickerNavgationController控制器
  3. 配置代理,注意不能直接设置代理,代理是父类(导航控制器)的代理,他的代理peoplePickerDelegate.
  4. 写代理方法
    已经被废弃了...
// 与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. 转化方式1:直接转化,对象所有权(谁负责生命周期管理)不会改变,还是C的生命周期.
    __bridge
    所以需要CFRelease()一下.

  2. 转化方式2:CFBridgingRelease(),等价于(__bridge_transer id)会转化对象的所有权,由ARC(编译期特性)负责.

OC的重点掌握
  1. 导入ContactUI框架
  2. CNContactPickerViewController
  3. 配置代理.
  4. 弹出控制器.

代理方法:

  1. 点击右上角取消按钮
  2. 选中了联系人
    1. 联系人具体信息
    2. 电话号码:多个电话号码,CNLabledValue:类似于字典.
  3. 选中多个联系人,选中单个的方法就不走了(类似2中的方法)
  4. 选中联系人属性
    4.1. 通用的代理方法,需要判断类型.如果是这个你需要的类型才作出处理.
    4.2. 判断选中的类型是否是电话号码.找到相关value,输出电话号码.
  5. 加一个属性,指定只显示的属性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  *phoneNumbers = contact.phoneNumbers;
    for (CNLabeledValue *labelValue in phoneNumbers) {
        // CNPhoneNumber 表示电话号码
        CNPhoneNumber *number = labelValue.value;
        NSLog(@"%@, %@", labelValue.label, number.stringValue);
    }
}

/**
 实现该代理方法, 支持多选, 选中单个联系人的代理方法失效
 */
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContacts:(NSArray *)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.1.2. 判断授权状态是否做出改变处理
    1.1.3. 请求授权.
  2. 遍历通讯录中所有联系人信息.
  3. 遍历获取电话号码对应的类型.

注意问题:

  1. 权限问题配置info.plist(产生崩溃)
  2. 在检索中没有使用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  *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:联系人数组

你可能感兴趣的:(通讯录技术)