iOS通讯录(纯纯的干货)
一、iOS8.0
1、访问用户通讯录的两个框架
(1)AddressBookUI.framework
提供了联系人列表界面、联系人详情界面、添加联系人界面等,一般用于选择联系人
(2)AddressBook.framework
<1>纯C语言的API,仅仅是获得联系人数据
<2>没有提供UI界面展示,需要自己搭建联系人展示界面
<3>里面的数据类型大部分基于Core Foundation框架,使用起来非常不方便
(3)从iOS6开始,需要得到用户的授权才能访问通讯录(没UI界面的),因此在使用之前,需要检查用户是否已经授权
获得通讯录的授权状态:ABAddressBookGetAuthorizationStatus()
2、使用AddressBookUI.framework示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | #import "ViewController.h" #import <AddressBookUI/AddressBookUI.h> @ interface ViewController () <ABPeoplePickerNavigationControllerDelegate> @end @implementation ViewController - ( void )viewDidLoad { [super viewDidLoad]; } - ( void )touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *) event { //创建通讯录控制器 //弹出控制器 ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc]init]; //设置代理 picker.peoplePickerDelegate = self; //展示通讯录界面 [self presentViewController:picker animated:YES completion:nil]; } //选中一个人的基本信息就会调用 //参数1:控制器 参数2:选择的person的信息 - ( void )peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person { /* 1、关于内存的管理:静态分析工具 2、因为是C语言的API(CoreFoundation),所有使用了create、copy等获取的对象都需要释放 -> CFRelease 3、桥接 __bridge 默认桥接 __bridge_transfer 桥接 coreF -> ocF 转让对象的所有权(释放权) __bridge_retained 桥接 ocF -> coreF 转让对象的所有权 */ //返回的ABRecordRef是一条记录,包括了一个人的所有信息字段 //通过“函数”获得姓名 CFStringRef strfirst = ABRecordCopyValue(person, kABPersonFirstNameProperty); CFStringRef strlast = ABRecordCopyValue(person, kABPersonLastNameProperty); //在桥接时,转让了对象的所有权,转给了OC来管理(自动释放了) NSString *strF = (__bridge_transfer NSString *)(strfirst); NSString *strL = (__bridge_transfer NSString *)(strlast); NSLog( @"%@ %@" ,strF,strL); //电话号码:ABMultiValueRef 封装一个保存了很多电话的一个类型,类似OC中的数组 ABMultiValueRef multiValues = ABRecordCopyValue(person, kABPersonPhoneProperty); //获得这个集合的数量(电话号码的数量) CFIndex index = ABMultiValueGetCount(multiValues); //遍历集合,打印电话 for (CFIndex i = 0; i < index; i++) { CFStringRef strPhone = ABMultiValueCopyValueAtIndex(multiValues, i); NSString *phoneStr = (__bridge_transfer NSString *)(strPhone); NSLog( @"%@" ,phoneStr); } //释放内存前,先判断该字段存在 if (multiValues != NULL) { CFRelease(multiValues); } } //选择中一个人信息的属性才会调用 //注意点:如果实现“选中个人信息的代理方法” 当前方法不执行,因为属性界面不会显示 - ( void )peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier { NSLog( @"property %zd" ,property); } //点击取消了 就会调用 - ( void )peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker { NSLog( @"peoplePickerNavigationControllerDidCancel" ); } |
3、使用AddressBook.framework框架示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | #import "ViewController.h" #import <AddressBook/AddressBook.h> @ interface ViewController () @end @implementation ViewController - ( void )viewDidLoad { [super viewDidLoad]; //获取用户的授权:授权状态 /* kABAuthorizationStatusNotDetermined = 0, // deprecated, use CNAuthorizationStatusNotDetermined kABAuthorizationStatusRestricted, // deprecated, use CNAuthorizationStatusRestricted kABAuthorizationStatusDenied, // deprecated, use CNAuthorizationStatusDenied kABAuthorizationStatusAuthorized // 已经授权 */ //通过函数获得授权状态 ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus(); if (status == kABAuthorizationStatusNotDetermined) { ABAddressBookRef book = ABAddressBookCreateWithOptions(NULL, NULL); //申请授权 //参数1 通讯录对象 参数2block 回调 ABAddressBookRequestAccessWithCompletion(book, ^( bool granted, CFErrorRef error) { if (granted) { NSLog( @"授权成功!" ); } else { NSLog( @"授权失败!" ); } }); } } - ( void )touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *) event { //获取联系人信息 //获得姓名 //通讯录是单例,在哪里获取都是一样的 ABAddressBookRef book = ABAddressBookCreateWithOptions(NULL, NULL); //获取所有人的信息 CFArrayRef allpeople = ABAddressBookCopyArrayOfAllPeople(book); //数量 CFIndex count = CFArrayGetCount(allpeople); for (CFIndex i = 0; i <count ; i++) { //获得没一条记录 ABRecordRef record = CFArrayGetValueAtIndex(allpeople, i); //获得姓名 CFStringRef strFirst = ABRecordCopyValue(record, kABPersonFirstNameProperty); NSString *str = (__bridge_transfer NSString *)strFirst; NSLog( @"%@" ,str); //获得电话号码 ABMultiValueRef multivalue = ABRecordCopyValue(record, kABPersonPhoneProperty); for (CFIndex i = 0; i < ABMultiValueGetCount(multivalue); i++) { CFStringRef phoneStr = ABMultiValueCopyValueAtIndex(multivalue, i); NSString *phone = (__bridge_transfer NSString *)(phoneStr); NSLog( @"%@" ,phone); } CFRelease(multivalue); } CFRelease(allpeople); CFRelease(book); } @end |
二、iOS9.0
1、访问用户通讯录的两个框架
(1)ContactsUI
<1>AddressBookUI的升级,不需要授权
<2>通过代理返回需要的数据
(2)Contacts
AddressBook.framework 的升级
2、ContactsUI示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #import "ViewController.h" #import <ContactsUI/ContactsUI.h> @ interface ViewController ()<CNContactPickerDelegate> @end @implementation ViewController - ( void )touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *) event { //不需要授权 //创建通讯录控制器 CNContactPickerViewController *picker = [[CNContactPickerViewController alloc]init]; //设置代理拿到数据本身 picker. delegate = self; //展示通讯录 [self presentViewController:picker animated:YES completion:nil]; } //实现代理方法 //选择一个联系人的基本信息 - ( void )contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact; { //重点注意contact的类型和属性 NSArray *allArray = contact.phoneNumbers; for (CNLabeledValue * labeledValue in allArray) { CNPhoneNumber *num = labeledValue.value; NSLog( @"num = %@" ,num.stringValue); NSLog( @"===%@ ===%@" ,labeledValue.value,labeledValue.label); } } //选择一个联系人属性信息 - ( void )contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty; { NSLog( @"didSelectContactProperty" ); } @end |
3、Contacts示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #import "ViewController.h" #import <Contacts/Contacts.h> @ interface ViewController () @property (nonatomic, strong) CNContactStore *store; @end @implementation ViewController - ( void )viewDidLoad { [super viewDidLoad]; //获取授权状态 CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]; //如果没有授权过需要请求用户的授权 CNContactStore *store = [[CNContactStore alloc]init]; self.store = store; if (status == CNAuthorizationStatusNotDetermined) { //请求授权 [store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) { if (granted) { NSLog( @"授权成功!" ); } else { NSLog( @"授权失败!" ); } }]; } } - ( void )touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *) event { //name phone CNContactFetchRequest *request = [[CNContactFetchRequest alloc]initWithKeysToFetch:@[CNContactGivenNameKey,CNContactPhoneNumbersKey]]; //参数1 封装查询请求 [self.store enumerateContactsWithFetchRequest: request error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) { //返回的数据 CNContact NSLog( @"%@" ,contact.givenName); NSLog( @"%@" ,contact.phoneNumbers); }]; } @end |
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现