iOS开发------获取系统联系人(Contacts篇)

本文介绍如何在iOS开发中使用Contacts.framework替代AddressBook获取系统联系人。内容涵盖权限描述、CNContactStore的使用、遍历请求类-CNContactFetchRequest、键值描述协议-CNKeyDescriptor以及各种联系人属性的获取方法。同时,讨论了在不同iOS版本下的适配策略和通讯录变化的监听方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Contacts.framework是Apple在 iOS9.0 替代AddressBook.framework的框架,至于AddressBook是做什么的框架,楼主默认看到博文的开发者是知道的 O(∩_∩)O。

如果想了解AddressBook的使用欢迎查看一下楼主之前关于AddressBook的博文,本篇不做过多的缀余:
iOS开发——获取系统联系人(AddressBook篇)
iOS开发——操作通讯录(AddressBook篇)&通讯录UI(AddressBookUI篇)

每次iOS发布新的版本(甚至每年的WWDC大会举行完毕)很多敏锐的开发者都准备或者对新版本特性进行适配。当然这些大神肯定会在iOS9发布后在第一时间对通讯录功能进行适配,一些稍微不太敏锐的开发者鉴于AddressBook在iOS9下初次提醒以及讨厌适配的繁琐,也就不以为然。

但随着iOS10的发布,那么适配相关框架就显得格外重要(不是说AddressBook不能使用了,但为了项目的健壮性以及良好的体验性,还是非常建议第一时间适配的。当然,这句话不仅限于Contacts部分)。

如果大家的项目还需要适配iOS8(当然,大多数公司肯定是也不会抛弃iOS7的用户),那么使用AddressBook是必然的;但如果在iOS9+的系统上,楼主还是非常建议使用最新的Contacts.framework框架的.

个人推荐的主要是下面两点原因(来源于楼主查看官方文档,编写Demo以及使用instruments的体会):

  1. AddressBook与其他相关废弃框架相似一样 (ex:ALAsset-图片库),语言风格更接近于C语言(当然也可以说就是C语言),不在ARC管理之下(对于习惯使用ARC下的开发者算是不小的挑战),使用不太便利并容易造成内存泄露。

  2. 新的框架无论在查看开发文档、使用、读取速度还是灵活性都远好于废弃框架,内存泄露易于查找以及补漏。

这里还是要分享一下源码,楼主整合AddressBook.framework以及Contacts.framework的DEMO

预览图

左边为AddressBook框架进行的演示,右边为Contact框架进行的演示.
根据不同的版本进行自动适配,如果是iOS9,自动使用Contact.framework.

 


权限描述

在iOS10上由于权限有很多的坑,本博文的内容需要使用通讯录权限.
那么不要忘记在项目的info.plist文件中加入如下描述:Privacy - Contacts Usage Description,描述字符串:RITL want to use your Contacts(这个随意),尽可能的写点东西吧,听说如果不写上线可能会被Apple拒绝..

获取权限-CNContactStore

负责获得权限、请求权限以及执行操作请求的类就是CNContactStore,具体Demo中的代码如下:

/**
 检测权限并作响应的操作
 */
- (void)__checkAuthorizationStatus
{
    //这里有一个枚举类:CNEntityType,不过没关系,只有一个值:CNEntityTypeContacts
    switch ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts])
    {
            //存在权限
        case CNAuthorizationStatusAuthorized:
            //获取通讯录
            [self __obtainContacts:self.completeBlock];
            break;

            //权限未知
        case CNAuthorizationStatusNotDetermined:
            //请求权限
            [self __requestAuthorizationStatus];break;

            //如果没有权限
        case CNAuthorizationStatusRestricted:
        case CNAuthorizationStatusDenied://需要提示
            self.defendBlock();break;
    }
}


请求联系人列表-CNContactStore

这里有几种比较常用的思路

1.使用自带的枚举方法一次性获得所有的属性

// 使用枚举方法对所有的联系人对象(CNContact)进行列出,该方法是同步的
- (BOOL)enumerateContactsWithFetchRequest:(CNContactFetchRequest *)fetchRequest
                                    error:(NSError *__nullable *__nullable)error
                               usingBlock:(void (^)(CNContact *contact, BOOL *stop))block;

2.先获取所有联系人的identifier,再根据identifier读取联系人信息(Demo中使用的该思路)

// 通过identifer获得一个唯一的CNContact
- (nullable CNContact *)unifiedContactWithIdentifier:(NSString *)identifier
                                         keysToFetch:(NSArray<id<CNKeyDescriptor>> *)keys
                                               error:(NSError *__nullable *__nullable)error;


遍历请求类-CNContactFetchRequest

感觉这里介绍一下CNContactFetchRequest类还是有必要的,毕竟当初在这里也是浪费了点时间,它是一个遍历请求的类,我们可以通过初始化该类的实例对象,告诉contactStore我们需要遍历contact的某些属性:

//实例化CNContactFetchRequest对象,通过一个遍历键的描述数组
- (instancetype)initWithKeysToFetch:(NSArray <id<CNKeyDescriptor>>*)keysToFetch NS_DESIGNATED_INITIALIZER;


键值描述协议-CNKeyDescriptor

如果我们单纯的进入开发文档,我们会发现他是一个空协议,刚开始看到这里的时候楼主表示很蒙B

//没有任何的required和optional方法
@protocol CNKeyDescriptor <NSObject, NSSecureCoding, NSCopying>
@end

但很快就发现了下面这个Category

// //Allows contact property keys to be used with keysToFetch.
// 允许contact的属性键作为遍历的键
@interface NSString (Contacts) <CNKeyDescriptor>
@end

如果还是有点疑惑,那么相信看到下面就不会再有困惑了呢。没错,可以直接将下列字符串当成CNKeyDescriptor对象写入数组

//标识符
CONTACTS_EXTERN NSString * const CNContactIdentifierKey                      NS_AVAILABLE(10_11, 9_0);
//姓名前缀
CONTACTS_EXTERN NSString * const CNContactNamePrefixKey                      NS_AVAILABLE(<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值