毋庸置疑的编制程序姿势

通信录简介

通信录使用处境:

  1. 电商类的 App,设置收货人电话号码。
  2. 即时通信类 App,添加手提式有线电电话机联系人相知。

通信录获取方案:

① 、iOS 9 从前的通信录框架

  1. AddressBookUI.framework 框架

    1. 提供了关联人列表界面、联系人详情界面、添加联系人界面等。
    2. 一般用于采纳联系人。
  2. AddressBook.framework 框架

    1. 纯 C 语言的 API,仅仅是收获联系人数据。
    2. 平昔不提供 UI 界面突显,要求自身搭建沟通人出示界面。
    3. 个中的数据类型大多数基于 Core Foundation
      框架,使用起来炒鸡复杂。

贰 、 iOS 9 未来最新通讯录框架

  1. ContactsUI.framework 框架。

    • 拥有 AddressBookUI.framework
      框架的富有机能,使用起来特别的面向对象。
  2. Contacts.framework 框架。

    • 拥有 AddressBook.framework 框架的有所成效,不再是 C 语言的
      API,使用起来至极简单。

新近多个礼拜,作者使用 plantuml (Bell实验室出品了叁个极品绘图工具
graphviz,
这是2个包装版)把本身的绘图项目做了叁回周到的接口和类的可视化。使用了广大设计形式,包含:桥接、装饰器、生成器、抽象工厂。绘制完后,图像是极美观的,接口之间的并行和参数定义清晰优雅。相当漂亮貌!

iOS 9 在此以前的通信录框架

然并卵!

AddressBookUI

其一项目在开发之处已经背离了本人的有的感觉,对于程序设计的觉得。从自家对数据库和服务器的连年经历,使用基于数据表和多少表达的抽象结构,你总能得到最简便易用可扩展的软件结构。

落到实处步骤

壹 、创制采取联系人的控制器

// 创建联系人选择控制器    
ABPeoplePickerNavigationController *pvc = [[ABPeoplePickerNavigationController alloc] init];

② 、设置代理(用来接收用户挑选的关联人新闻)

// 设置代理
pvc.peoplePickerDelegate = self;

三 、弹出联系人控制器

if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined)
{
   ABAddressBookRef bookRef = ABAddressBookCreate();
   ABAddressBookRequestAccessWithCompletion(bookRef, ^(bool granted, CFErrorRef error) {
       if (granted)
       {
           NSLog(@"授权成功!");
           [self presentViewController:pvc animated:YES completion:nil];
       }
       else
       {
           NSLog(@"授权失败!");
       }
   });
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized)
{
   [self presentViewController:pvc animated:YES completion:nil];
}

肆 、完毕代理方法

// 选择某个联系人时调用
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person
{
    NSLog(@"选中联系人");
    CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
    CFStringRef lastName = ABRecordCopyValue(person, kABPersonLastNameProperty);

    NSString *fir = CFBridgingRelease(firstName);
    NSString *las = CFBridgingRelease(lastName);

    NSLog(@"%@---%@", fir, las);

    ABMultiValueRef multi = ABRecordCopyValue(person, kABPersonPhoneProperty);
    CFIndex count = ABMultiValueGetCount(multi);
    for (int i = 0; i  < count; i++) 
    {
        NSString *label = (__bridge_transfer NSString *)ABMultiValueCopyLabelAtIndex(multi, i);
        NSString *phone =(__bridge_transfer NSString *)  ABMultiValueCopyValueAtIndex(multi, i);
        NSLog(@"%@---%@", label, phone);
    }
}

Core Foundation 对象手动管理内部存储器,假使是 Create、Copy、Retain
等字样创立的对象,供给手动 CFRelease。类似 Objective-C 的 M奥迪Q7C。

拓展:__bridge__bridge_retained__bridge_transfer
多个转移关键字的界别。

  1. __bridge 只做类型转换,可是不改动对象(内部存款和储蓄器)管理权;
  2. __bridge_retained(也能够使用CFBridgingRetain)将 Objective-C
    的靶子转换为 Core Foundation
    的对象,同时将目的(内部存储器)的管理权交给大家,后续须求动用 CFRelease
    大概有关办法来刑释对象;
  3. __bridge_transfer(也能够应用 CFBridgingRelease )将 Core
    Foundation 的对象转换为 Objective-C
    的对象,同时将对象(内存)的管理权交给 A智跑C。

五 、在相应的代办方法中拿走联系人音讯

// 1.选择联系人时使用(不展开详情)
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person;

// 2.选择联系人某个属性时调用(展开详情)
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier;

// 3.取消选中联系人时调用
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker;

留神:选择联系人的不举行详情(代理方法1)和开始展览详情(代理方法2)的代办方法都写了的时候,展开详情的代理方法就不实施。

唯独,那么些绘图项目真正很复杂,涉及了诸多的多态和关联。比如,在2个长的列表中蕴藏种类分歧的图形,这几个图片存款和储蓄的绘图数据和有关消息都不比,作者索要把那些多少视做同一种档次,然后迭代它们,选出须要的一个同时使用它的有关新闻。所以,笔者尝试运用学术界的设计方式来消除在那之中的难点。

AddressBook

一 、请求授权

从 iOS 6
起头,必要取得用户的授权才能访问通讯录,因而在动用从前,需求检查用户是还是不是早已授权。

// 获得通讯录的授权状态
ABAddressBookGetAuthorizationStatus()

授权意况

  1. 用户还从未控制是还是不是授权你的先后进行访问:kABAuthorizationStatusNotDetermined

  2. iOS
    设备上有的准许配置阻止程序与通信录数据库实行互动:kABAuthorizationStatusRestricted

  3. 用户鲜明的不容了你的先后对通信录的访问:kABAuthorizationStatusDenied

  4. 用户已经授权给您的次第对通信录举办访问:kABAuthorizationStatusAuthorized

// 判断当前的授权状态是否是用户还未选择的状态
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) 
{
   ABAddressBookRef bookRef = ABAddressBookCreate();
   ABAddressBookRequestAccessWithCompletion(bookRef, ^(bool granted, CFErrorRef error) {
       if (granted) 
       {
           NSLog(@"授权成功!");
       }
       else
       {
           NSLog(@"授权失败!");
       }
   });
}

② 、判断授权景况

假诺已授权,则延续;未授权,则提示用户,并回到。

// 判断当前的授权状态
if (ABAddressBookGetAuthorizationStatus() != kABAuthorizationStatusAuthorized) 
{
    NSLog(@"您的通讯录暂未允许访问,请去设置->隐私里面授权!");
    return;
}

三 、创设通讯录对象

// 创建通讯录对象
ABAddressBookRef bookRef = ABAddressBookCreate();

四 、从通讯录对象中, 获取具有的联络人

// 获取通讯录中所有的联系人
CFArrayRef arrayRef = ABAddressBookCopyArrayOfAllPeople(bookRef);

五 、遍历全数的牵连人

// 遍历所有联系人
CFIndex count = CFArrayGetCount(arrayRef);
for (int i = 0; i < count; i++) 
{
   ABRecordRef record = CFArrayGetValueAtIndex(arrayRef, i);

   // 获取姓名
   NSString *firstName = (__bridge_transfer NSString *)ABRecordCopyValue(record, kABPersonFirstNameProperty);
   NSString *lastName = (__bridge_transfer NSString *)ABRecordCopyValue(record, kABPersonLastNameProperty);
   NSLog(@"firstName = %@, lastName = %@", firstName, lastName);

   // 获取电话号码
   ABMultiValueRef multiValue = ABRecordCopyValue(record, kABPersonPhoneProperty);
   CFIndex count = ABMultiValueGetCount(multiValue);
   for (int i = 0; i < count; i ++) 
   {
       NSString *label = (__bridge_transfer NSString *)ABMultiValueCopyLabelAtIndex(multiValue, i);
       NSString *phone = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(multiValue, i);
       NSLog(@"label = %@, phone = %@", label, phone);
   }

   CFRelease(multiValue);
}

6、释放不再选取的靶子

CFRelease(bookRef);
CFRelease(arrayRef);

当项目变得很巨大的时候,作者发现到设计形式屁都不是。诸如桥接、装饰器以及其余,都以树立在一种借使,倘诺你的父组件和子组件总是能够忽略对方的细节,而能够统一的处理它们。比如,面包有奶油味、抹茶味、水果味,面包又有起码材质、高档质感,那么您能够把味道和素材分为五个例外的接口,然后分别抽象,并且结合那三个接口生成更拉长的面包,比如低档质地的抹茶味面包。不过,真实的编制程序世界中,那样的优质状态很是少。在真正的编制程序世界中,面包还想要越来越多的东西,比如奶油味的有糖,抹茶味的没有糖,有糖的面包放在左边柜台上,没有糖的面包放在左侧柜台上。看到了吧,复杂度升级了,柜台跟面包有没有糖是绑定的。那代表,假使您想像前边那么抽象两个接口—味道和资料,那您以后必须考虑柜台。因为低档质地的抹茶味面包是平昔不糖的,放在右侧柜台。以往,你只可以抽象出味道和柜台的涉及。在地方的接口之上再追加一层。每当你的需求复杂一点,那种层就会升级。比如,红糖面包和白糖面包。

关系人属性定义

拥有的习性常量值都定义在了 ABPerson.h 头文件中。

关系人属性蕴涵以下项目:

  1. 不难易行属性:姓、名等
  2. 多重属性:电话号码、电子邮件等
  3. 组合属性:地址等

语言,注意:使用 ABRecordCopyValue 能够从一条 Person
记录中获取到对应的笔录,不过后续处理则要求依据记录的现实性项目加以不相同。

总的说来,固然设计方式制止了类继承的爆炸,不过也幸免不了抽象层级的复杂性。

大约属性

二个关联人正是1个
ABRecordRef,每一个联系人都有本人的性质,比如名字、电话、邮件等。
使用 ABRecordCopyValue 函数能够从 ABRecordRef
中获得联系人的粗略属性(例如:1个字符串)。
ABRecordCopyValue 函数接收 2 个参数。
第 1 个参数是 ABRecordRef 实例。
第 2 个参数是性质关键字,定义在 ABPerson.h 中。
ABPersonCopyLocalizedPropertyName
函数能够依照钦点的第叁字获取相应的标签文本。

从而,我认为自个儿又不会编程了。于是,笔者尽量的再一次考虑那些规划,并且重新在网络上摸索曾经协助自身的安顿性论调:面向数据结构编制程序而不是指标。假使不是为着那几个绘图项目,小编相对不会铤而走险再一遍利用设计形式和面向对象。

收获全数的沟通人多少

// 获取所有联系人记录
CFArrayRef array = ABAddressBookCopyArrayOfAllPeople(addressBook);
NSInteger count = CFArrayGetCount(array);

for (NSInteger i = 0; i < count; ++i) {
    // 取出一条记录
    ABRecordRef person = CFArrayGetValueAtIndex(array, i);

    // 取出个人记录中的详细信息
    // 名
    CFStringRef firstNameLabel = ABPersonCopyLocalizedPropertyName(kABPersonFirstNameProperty);
    CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
    CFStringRef lastNameLabel = ABPersonCopyLocalizedPropertyName(kABPersonLastNameProperty);
    // 姓
    CFStringRef lastName = ABRecordCopyValue(person, kABPersonLastNameProperty);

    NSLog(@"%@ %@ - %@ %@", lastNameLabel, lastName, firstNameLabel, firstName);
}

自家当然搜到了一大堆 Linus 排斥面向对象和 C++ Java
的说话,从感觉上,那么些正是笔者面临设计困难时候的感到。小编曾经无多次那样消除本人的次序设计。

CoreFoundation 与 Foundation之间的桥接

// 1. 获取通讯录引用
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, nil);
// 2. 获取所有联系人记录
NSArray *array = (__bridge NSArray *)(ABAddressBookCopyArrayOfAllPeople(addressBook));
for (NSInteger i = 0; i < array.count; i++) {
    // 取出一条记录
    ABRecordRef person = (__bridge ABRecordRef)(array[i]);
    // 取出个人记录中的详细信息
    NSString *firstNameLabel = (__bridge NSString *)(ABPersonCopyLocalizedPropertyName(kABPersonFirstNameProperty));
    NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonFirstNameProperty));
    NSString *lastNameLabel = (__bridge NSString *)(ABPersonCopyLocalizedPropertyName(kABPersonLastNameProperty));
    NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonLastNameProperty));
    NSLog(@"%@ %@ - %@ %@", lastNameLabel, lastName, firstNameLabel, firstName);
}
CFRelease(addressBook);

git的计划性其实10分的简便,它的数据结构很稳定,并且有增进的文书档案描述。事实上,作者特别的倾向应该围绕大家的数据结构来设计代码,而不是基于其余的,笔者认为那也是git之所以成功的缘故之一。[…]
依笔者的视角,好程序员和烂程序员之间的差距就在于他们以为是代码更首要还是数据结构更要紧。

在庞大的品种中,人们对不是协调付出的模块并不打听,能便捷领悟别的模块中等校园函授数的恰到好处含义才能增高支付功能。而C++引入的各个抽象则使代码相当正视上下文,想驾驭一段代码,供给看多得多的上下文。

面向对象语言以指标为着力,加一些相关联的主意,简直是呓语。首要的东西应该是数据结构,对象自小编有甚主要?真正有意思的,是在差别品类的两样对象交互而且有锁规则的时候。然则,即便是此时,封装什么“对象接口”也断然大错特错,因为不再是纯净对象的题目了。

多重属性

联系人的略微属性值就没这样不难,2脾特性大概会含有八个值
比如说邮箱,分为工作邮箱、住宅信箱、其余邮箱等
比如电话,分为工作电话、住宅电话、其余电话等
要是是繁体属性,那么 ABRecordCopyValue 函数再次来到的正是
ABMultiValueRef 类型的多少,例如邮箱恐怕电话

// 取电话号码
ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
// 取记录数量
NSInteger phoneCount = ABMultiValueGetCount(phones);
// 遍历所有的电话号码
for (NSInteger i = 0; i < phoneCount; i++) 
{

}

诙谐的是,这里有一篇别的1人长辈的很早的文字,推在 谷歌+ 上,来自 Unix
大旨创造者之一 罗布 Pike:

赢得复杂属性的主意

// 电话标签
CFStringRef phoneLabel = ABMultiValueCopyLabelAtIndex(phones, i);
// 本地化电话标签
CFStringRef phoneLocalLabel = ABAddressBookCopyLocalizedLabel(phoneLabel);
// 电话号码
CFStringRef phoneNumber = ABMultiValueCopyValueAtIndex(phones, i);

最初的小说链接
A few years ago I saw this page:
http://www.csis.pace.edu/~bergin/patterns/ppoop.html

Local discussion focused on figuring out whether this was a joke or
not. For a while, we felt it had to be even though we knew it wasn’t.
Today I’m willing to admit the authors believe what is written there.
They are sincere.

But… I’d call myself a hacker, at least in their terminology, yet my
solution isn’t there. Just search a small table! No objects required.
Trivial design, easy to extend, and cleaner than anything they
present. Their “hacker solution” is clumsy and verbose. Everything
else on this page seems either crazy or willfully obtuse. The lesson
drawn at the end feels like misguided epistemology, not technological
insight.

It has become clear that OO zealots are afraid of data. They prefer
statements or constructors to initialized tables. They won’t write
table-driven tests. Why is this? What mindset makes a multilevel type
hierarchy with layered abstractions better than searching a three-line
table? I once heard someone say he felt his job was to remove all
while loops from everyone’s code, replacing them with object stuff.
Wat?

But there’s good news. The era of hierarchy-driven, keyword-heavy,
colored-ribbons-in-your-textook orthodoxy seems past its peak. More
people are talking about composition being a better design principle
than inheritance. And there are even some willing to point at the
naked emperor; see
http://prog21.dadgum.com/156.html
for example. There are others. Or perhaps it’s just that the old guard
is reasserting itself.

Object-oriented programming, whose essence is nothing more than
programming using data with associated behaviors, is a powerful idea.
It truly is. But it’s not always the best idea. And it is not well
served by the epistemology heaped upon it.

Sometimes data is just data and functions are just functions.

— Rob Pike (One of the Unix creators (Ken Thompson, Dennis M.
Ritche, and Rob Pike))

几年前本人见状了这么些网页:
http://www.csis.pace.edu/~bergin/patterns/ppoop.html

自作者真正不明白这篇小说到底是否在搞笑。读了瞬间,小编固然很想说那不是一篇搞笑的篇章,可是,拜托,它根本就是。让自个儿来跟你们讲讲他们在搞笑什么吧。

e…根据他们的话语,笔者应当称自身为 hacker
(黑客),不管作者不关怀这么些。Hello! 你只供给三个小的不可能再小的 table

根本不需求如何目的。朴素平凡,简单扩大,不难清除,(比起他们的那种设计)多
TM 简单。他们的 “hacker solution”
真的是又蠢又笨。他们写出来的这堆东西四处透漏着疯狂和鸠拙。他们缺乏技术认知。

很明确,OO 的狂热者们心惊肉跳数据。他们喜欢用讲话或然组织器来初步化 tables
。他们平素不写 table-driven 的测试。Why is this?
得有多大的心才会选用用一体系并且多层的类华而不实,而不去用贰个小小三行
table ? 作者曾经听别人讲有人用各个 OO 的事物替换掉 while 循环。

可是好消息是,hierarchy-driven, keyword-heavy,
colored-ribbons-in-your-textook orthodoxy
这个东东快到头了。愈来愈多的人挑选组合而不是继承。有些人已经再一次开头认识
OO。

面向对象编制程序语言,其本意是应用数据和连锁的一言一行开始展览编程,那是1个很好的想法。事实真的如此。可是,这几个想法并不三番五次最好的
idea。 那么些想法并不曾完全的认知编制程序的社会风气。

Sometimes data is just data and functions are just functions.

— 罗布 Pike (Unix 创立者之一的 (Ken 汤普森, Dennis M. Ritche, and
罗布 Pike))

拉长关系人的步骤

加上挂钩人的步子:

  1. 通过 ABPersonCreate 函数创设2个新的联络员(重临 ABRecordRef)。
  2. 通过 ABRecordSetValue 函数设置联系人的天性。
  3. 通过 ABAddressBookAddRecord 函数将联系人添加到通信录数据库中。
  4. 通过 ABAddressBookSave 函数保存刚才所作的修改。

能够通过 ABAddressBookHasUnsavedChanges 函数判断是或不是有未保存的修改
当控制是或不是改变通信录数据库后,你能够独家接纳 AbAddressBookSave
ABAddressBookRevert 方式来保存或扬弃更改 。

科学,大家必要的正是数码的抽象和数目标解释器。用表来存款和储蓄你须求的顺序数据,对于多态,C
语言中总结直接干净:union。使用那样1个简便的结构,你能积存种种分化的门类,而且你只必要仓库储存他们的指针,那象征你不会浪费多少内部存储器,同时你能取得一致内部存款和储蓄器段但是多少分化的画饼充饥。

加上群组的步调

添加群组的手续大体和添加联络官一致:

  1. 通过 ABPersonCreate 函数创建一个新的组。(重临 ABRecordRef
  2. 通过 ABRecordSetValue 函数设置组名。
  3. 通过 ABAddressBookAddRecord 函数将组添加到通信录数据库中。
  4. 通过 ABAddressBookSave 函数保存刚才所作的改动。

接下来,使用多少个链表或许数组,把那一个 union
装进去,遍历,cast,然后选择你要求的特定数据。

操香港作家联谊会系人的头像

想操香港作家联谊会系人的头像,有以下函数
BPersonHasImageData
看清通信录中的联系人是不是有图表

ABPersonCopyImageData
赢得图片数据(固然有些话)

ABPersonSetImageData
安装联系人的图形数据

重重言语都有 union 的变体,现代语言中的泛型正是 union
的一种语法糖,可是你往往忘记了那种结构的实在价值和用意。仔细回味下这些全新的统一筹划:

通信录的改动回调

// 创建通讯录
self.addressBook = ABAddressBookCreate();  
// 注册通知  
ABAddressBookRegisterExternalChangeCallback(self.addressBook, _addressBookChange, nil);            

// 处理收到通知的 Action
void _addressBookChange(ABAddressBookRef addressBook, CFDictionaryRef info, void *context)
{
}

- (void)dealloc
{
    // 注销通知
    ABAddressBookUnregisterExternalChangeCallback(self.addressBook, _addressBookChange, nil);
    // 释放对象
    CFRelease(self.addressBook);
}
enum ShapeKind {
  skLINE, skPORT, skBOARD
}

class Shape {
  kind: ShapeKind   
  value: Line | Port | Board
  contains(x: number, y: number): boolean
}

class ShapeContainer {
  shapes: Array<Shape>
  search(x: number, y: number): [ShapeKind, Shape]
}

type
  ShapeKind = enum
    skLINE, skPORT, skBOARD

  Shape = ref object
    case kind: ShapeKind
    of skLINE:
      line: Line
    of skPORT:
      port: Port
    of skBOARD:
      board: Board
    contains: (x: number, y: number): bool

  ShapeContainer = object
    shapes: seq[Shape]

proc search(c: ShapeContainer, x: number, y: number): tuple[kind: ShapeKind, shape: Shape]

iOS 9 今后的简报录新框架

iOS 9 在此以前操作通信录依然比较麻烦的,iOS 9
以往苹果推出了崭新的通信录框架,使用起来更为的面向对象。

CNContactUI

贯彻步骤

① 、成立选取联系人的控制器

// 创建联系人选择控制器    
CNMutableContact *contact = [[CNMutableContact alloc] init];
CNLabeledValue *labelValue = [CNLabeledValue labeledValueWithLabel:CNLabelPhoneNumberMobile
ontact.phoneNumbers = @[labelValue];                                                                     value:[CNPhoneNumber phoneNumberWithStringValue:phoneNum]];
CNContactViewController *contactController = [CNContactViewController viewControllerForNewContact:contact];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:contactController];

二 、设置代理(用来收纳用户选拔的关联人新闻)

// 设置代理
contactController.delegate = self;

三 、弹出联系人控制器

[controller presentViewController:nav animated:YES completion:nil];

肆 、达成代理方法

// 选择某个联系人时调用
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty
{
    CNContact *contact = contactProperty.contact;
    NSString *name = [CNContactFormatter stringFromContact:contact style:CNContactFormatterStyleFullName];
    CNPhoneNumber *phoneValue= contactProperty.value;
    NSString *phoneNumber = phoneValue.stringValue;
    NSLog(@"%@--%@",name, phoneNumber);
}

5、在对应的代理方法中取得联系人新闻

// 1.选择联系人时使用(不展开详情)
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact;

// 2.选择联系人某个属性时调用(展开详情)
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty;

// 3.取消选中联系人时调用
- (void)contactPickerDidCancel:(CNContactPickerViewController *)picker;

瞩目:与 AddressBookUI
一样,选用联系人的不举行详情(代理方法1)和拓展详情(代理方法2)的代理方法都写了的时候,展开详情的代办方法就不履行。

CNContact

落到实处步骤

一 、请求授权

// 获得通讯录的授权状态
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]

授权意况

  1. 用户还没有决定是还是不是授权你的次序开始展览走访:CNAuthorizationStatusNotDetermined

  2. iOS
    设备上一些认同配置阻止程序与通讯录数据库进行交互:CNAuthorizationStatusRestricted

  3. 用户明显的不容了您的次第对通信录的拜访:CNAuthorizationStatusDenied

  4. 用户已经授权给你的先后对通信录实行走访:CNAuthorizationStatusAuthorized

// 判断当前的授权状态是否是用户还未选择的状态
if (status == CNAuthorizationStatusNotDetermined)
{
    CNContactStore *store = [CNContactStore new];
    [store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (granted) 
        {
            NSLog(@"授权成功!");
        }
        else
        {
            NSLog(@"授权失败!");
        }
    }];
}

贰 、判断授权意况

如若已授权,则继续;未授权,则提示用户,并赶回。

// 判断当前的授权状态
if (status != CNAuthorizationStatusAuthorized) 
{
    NSLog(@"您的通讯录暂未允许访问,请去设置->隐私里面授权!");
    return;
}

叁 、制造通信录对象

// 创建通讯录对象
CNContactStore *contactStore = [CNContactStore new];

肆 、设置访问的质量 Key,每一个 Key 对应1性子子,iOS 9
新增,借使没有安装,访问该属性就会崩溃。

// 姓名前缀
CNContactNamePrefixKey     
// 名                 
CNContactGivenNameKey                       
// 中间名
CNContactMiddleNameKey  
// 姓                   
CNContactFamilyNameKey            
// 婚前姓         
CNContactPreviousFamilyNameKey
// 姓名后缀
CNContactNameSuffixKey   
// 昵称                   
CNContactNicknameKey                        
// 公司
CNContactOrganizationNameKey                
// 部门
CNContactDepartmentNameKey                  
// 职位
CNContactJobTitleKey                        
// 名字拼音或音标
CNContactPhoneticGivenNameKey
// 中间名拼音或音标              
CNContactPhoneticMiddleNameKey
// 姓拼音或音标
CNContactPhoneticFamilyNameKey  
// 公司拼音或音标            
CNContactPhoneticOrganizationNameKey      
// 生日  
CNContactBirthdayKey   
// 农历                    
CNContactNonGregorianBirthdayKey    
// 备注        
CNContactNoteKey                            
// 图片
CNContactImageDataKey                       
// 缩略图
CNContactThumbnailImageDataKey              
// 图片是否允许访问
CNContactImageDataAvailableKey              
// 类型
CNContactTypeKey                            
// 号码
CNContactPhoneNumbersKey                    
// 电子邮件
CNContactEmailAddressesKey                  
// 地址
CNContactPostalAddressesKey                 
// 日期
CNContactDatesKey   
// URL                        
CNContactUrlAddressesKey                    
// 关联人
CNContactRelationsKey                       
// 社交
CNContactSocialProfilesKey                  
// 即时通讯
CNContactInstantMessageAddressesKey         

NSArray *keys = @[CNContactPhoneNumbersKey,CNContactGivenNameKey];

伍 、从通讯录对象中, 获取具有的联络人,并遍历

// 获取通讯录中所有的联系人
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:keys];

[contactStore enumerateContactsWithFetchRequest:request error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
    // 获取姓名
    NSString *firstName = contact.familyName;
    NSString *lastName = contact.givenName;

    NSLog(@"%@--%@",firstName,lastName);

    // 获取电话号码

    for (CNLabeledValue *labeledValue in contact.phoneNumbers)
    {
         CNPhoneNumber *phoneValue = labeledValue.value;
         NSString *phoneNumber = phoneValue.stringValue;
         NSString *label = [CNLabeledValue localizedStringForLabel:labeledValue.label];
         NSLog(@"%@--%@",label,phoneNumber);
    }

}];

通讯录的修改回调

// 注册通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_contactStoreDidChange) name:CNContactStoreDidChangeNotification object:nil]            

// 处理收到通知的 Action
- (void)_contactStoreDidChange
{
}

- (void)dealloc
{   
    // 注销通知
    [[NSNotificationCenter defaultCenter] removeObserver:self name:CNContactStoreDidChangeNotification object:nil];
}

当 App
活跃(前台+后台活动之间)的时候,当通信录修改的时候,会接收公告
当 App 不活跃的时候(挂起的时候),App 收不到文告;而是,当 App
到前台的时候接到延迟的布告。

LJContactManager

介绍

LJContanctManager 是本人写的一款操作通信录的类库,iOS 9 以前运用的是
AddressBook 和 AddressBookUI 系统库,iOS 9 之后接纳苹果新生产的 Contacts
和 ContactsUI 框架。

安装

CocoaPods

  1. 在 Podfile 中添加 pod 'LJContactManager'
  2. 执行 pod installpod update
  3. 导入 <LJContactManager.h>。

手动安装

  1. 下载 LJContactManager 文件夹内的兼具情节。
  2. 将 LJContactManager 内的源文件添加(拖放)到你的工程。
  3. 导入 LJContactManager.h

使用

要害提供以下的章程:

  • 挑选联系人

/**
 选择联系人

 @param controller 控制器
 @param completcion 回调
 */
- (void)selectContactAtController:(UIViewController *)controller
                      complection:(void (^)(NSString *name, NSString *phone))completcion;
  • 创建新关系人

/**
 创建新联系人

 @param phoneNum 手机号
 @param controller 当前 Controller
 */
- (void)createNewContactWithPhoneNum:(NSString *)phoneNum controller:(UIViewController *)controller;
  • 增进到现有联系人

/**
 添加到现有联系人

 @param phoneNum 手机号
 @param controller 当前 Controller
 */
- (void)addToExistingContactsWithPhoneNum:(NSString *)phoneNum controller:(UIViewController *)controller;
  • 收获联系人列表(未分组的通信录)

/**
 获取联系人列表(未分组的通讯录)

 @param completcion 回调
 */
- (void)accessContactsComplection:(void (^)(BOOL succeed, NSArray <LJPerson *> *contacts))completcion;
  • 获得联系人列表(已分组的通讯录)

/**
 获取联系人列表(已分组的通讯录)

 @param completcion 回调
 */
- (void)accessSectionContactsComplection:(void (^)(BOOL succeed, NSArray <LJSectionPerson *> *contacts, NSArray <NSString *> *keys))completcion;
  • 报道录变更回调(未分组的通信录)

/**
 通讯录变更回调(未分组的通讯录)
 */
@property (nonatomic, copy) void (^contactsChangeHanlder) (BOOL succeed, NSArray <LJPerson *> *newContacts);
  • 报道录变更回调(已分组的通信录)

/**
 通讯录变更回调(已分组的通讯录)
 */
@property (nonatomic, copy) void (^sectionContactsHanlder) (BOOL succeed, NSArray <LJSectionPerson *> *newSectionContacts, NSArray <NSString *> *keys);

最后

出于小编水平有限,文中假如有荒唐的地点,也许有更好的主意,还望大神建议。
屈居本文的具有 demo
下载链接,【GitHub】
一经您看完后认为对你有着辅助,还望在 GitHub 上点个
star。赠人玫瑰,手有余香。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图