iOS中通讯录的开发
通讯录开发主要是获取用户手机中的联系人,进而可以在应用中添加好友
一 .如何访问通讯录
(1)在iOS9之前,有两个框架可以访问用户的通讯录
AddressBookUI.framework: 提供了联系人列表界面,联系人详情界面,添加练习人界面等,一般用于选择联系人
AddressBook.framework: 纯C语言的API,仅仅是获的联系人数据,没有提供UI界面展示,需要自己搭建联系人展示界面,里面的数据类型大部分基于Core Foundation框架,使用起来极其蛋疼
(2)在iOS9开始,也有两个框架可以访问用户的通讯录
ContactsUI.framework: 对应AddressBookUI.framework
Contacts.framework: 对应AddressBook.framework
二.代码演示
(1)AddressBookUI的使用
使用步骤
1)创建选择联系人控制器
2)设置代理
3)实现代理方法(在代理方法中拿到用户选择的联系人)
4)弹出控制器
代码如下:
import UIKit
import AddressBookUI class ViewController: UIViewController { override func viewDidLoad() {
super.viewDidLoad()
} override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// 1.创建联系人选择的控制器
let ppnc = ABPeoplePickerNavigationController() // 2.设置代理
ppnc.peoplePickerDelegate = self // 3.弹出控制器
present(ppnc, animated: true, completion: nil)
}
} extension ViewController : ABPeoplePickerNavigationControllerDelegate {
// 用户选中了某一个联系人
func peoplePickerNavigationController(_ peoplePicker: ABPeoplePickerNavigationController, didSelectPerson person: ABRecord) {
// 1.获取联系人的姓名
/*
Unmanaged<CFTypeRef>? : 非托管对象
* 在Swift和C语言进行混编的过程中,产生的一个临时对象,真正使用的时候需要将非托管对象,转成真正的对象才能进行使用
* takeUnretainedValue : 表示在转化的过程中,不会对对象进行一次retain操作
* takeRetainedValue : 表示在转化的过程中,有对对象进行一次retain操作
注意:一旦使用takeRetainedValue,那么必须对之前的非托管对象进行一次release(),否则就会产生内存泄漏
let UnManageObjc = ABRecordCopyValue(person, kABPersonLastNameProperty)
let lastname = UnManageObjc?.takeRetainedValue() as? String
UnManageObjc?.release()
*/
guard let lastname = ABRecordCopyValue(person, kABPersonLastNameProperty).takeUnretainedValue() as? String else { return }
guard let firstname = ABRecordCopyValue(person, kABPersonFirstNameProperty).takeUnretainedValue() as? String else { return }
print("姓名:\(firstname) \(lastname)") // 2.获取联系人的电话号码
// ABMultiValue 类似于一个字典,里面有key/value
// 2.1.从person中拷贝出来所有的电话号码
let phones = ABRecordCopyValue(person, kABPersonPhoneProperty).takeUnretainedValue() as ABMultiValue
// 2.2.遍历ABMultiValue中的所有电话
// guard let count = phones.count else { return } 错误写法
let count = ABMultiValueGetCount(phones) for i in ..<count {
let phoneLabel = ABMultiValueCopyLabelAtIndex(phones, i).takeUnretainedValue() as String
guard let phoneValue = ABMultiValueCopyValueAtIndex(phones, i).takeUnretainedValue() as? String else { continue }
print("phoneLabel:\(phoneLabel) phoneValue:\(phoneValue)")
}
}
}
注意: 这里有一种对象 :Unmanaged<CFTypeRef>? : 非托管对象,这种对象是在Swift和C语言进行混编的过程中,出现的.需要用takeUnretainedValue() 或者 takeRetainedValue()进行转化.
运行结果如下图:
(2)AddressBook的使用
1)获取用户的授权
获取授权状态
如果用户是未决定状态,则请求授权
2)获取联系人信息
获取授权状态
如果是已经授权,则获取联系人信息
创建通讯录对象
获取通信录中所有的联系人
遍历所有的联系人,获取联系人信息
获取用户授权的代码实现,通常在应用启动时就询问用户授权
AppDelegate中代码如下所示:
import UIKit
import AddressBook @UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // 1.获取用户的授权状态
let status = ABAddressBookGetAuthorizationStatus() // 2.判断授权状态是否未决定
if status == .notDetermined {
// 2.1.创建通信录对象
let addressBook = ABAddressBookCreate().takeUnretainedValue() // 2.2.请求授权
ABAddressBookRequestAccessWithCompletion(addressBook, { (isFlag : Bool, error : CFError?) in
if isFlag {
print("授权成功")
} else {
print("授权失败")
}
})
} return true
}
}
ViewController中代码如下所示:
import UIKit
import AddressBook class ViewController: UIViewController { override func viewDidLoad() {
super.viewDidLoad()
} override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// 1.获取用户授权状态
let status = ABAddressBookGetAuthorizationStatus() // 2.判断是否是已经授权
guard status == .authorized else {
return
} // 3.创建通信录对象
let addressBook = ABAddressBookCreate().takeUnretainedValue() // 4.从对象中,拷贝出来所有的联系人
let peopleArray = ABAddressBookCopyArrayOfAllPeople(addressBook).takeUnretainedValue() // 5.遍历数组,获取每一个联系人
let count = CFArrayGetCount(peopleArray)
for i in ..<count {
// 5.1.获取指针
let pointer = CFArrayGetValueAtIndex(peopleArray, i) // 5.2.获取指针指向的对象
// unsafeBitCast : 将指针转成某一个对象
let person = unsafeBitCast(pointer, to: ABRecord.self) // 5.3.获取该联系人的姓名
guard let lastname = ABRecordCopyValue(person, kABPersonLastNameProperty).takeUnretainedValue() as? String else { continue }
guard let firstname = ABRecordCopyValue(person, kABPersonFirstNameProperty).takeUnretainedValue() as? String else { continue }
print("姓名:\(firstname) \(lastname)") // 5.4.获取电话号码
let phones = ABRecordCopyValue(person, kABPersonPhoneProperty).takeUnretainedValue() as ABMultiValue
let phoneCount = ABMultiValueGetCount(phones)
for i in ..<phoneCount {
// let phoneLabel = ABMultiValueCopyLabelAtIndex(phones, i).takeUnretainedValue() as String
guard let phoneValue = ABMultiValueCopyValueAtIndex(phones, i).takeUnretainedValue() as? String else { continue }
print(phoneValue)
}
}
}
}
注意: 由于需要访问请求授权,需要在info.plist配置NSContactsUsageDescription这个key
(3)ContactsUI的使用
1)使用步骤
创建选择联系人控制器
设置代理
实现代理方法(在代理中拿到用户选择的联系人)
弹出控制器
2)代码实现
import UIKit
import ContactsUI class ViewController: UIViewController { override func viewDidLoad() {
super.viewDidLoad()
} override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// 1.创建联系人选择的控制器
let cpvc = CNContactPickerViewController() // 2.设置代理
cpvc.delegate = self // 3.弹出控制器
present(cpvc, animated: true, completion: nil)
}
} extension ViewController : CNContactPickerDelegate {
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
// 1.获取用户的姓名
// lastname --> familyName
// firstname --> givenname
let lastname = contact.familyName
let firstname = contact.givenName
print("姓名:\(firstname) \(lastname)") // 2.获取用户电话号码(ABMultivalue)
let phones = contact.phoneNumbers
for phone in phones {
let phoneLabel = phone.label
let phoneValue = phone.value.stringValue
print("phoneLabel:\(phoneLabel). phoneValue:\(phoneValue)")
}
} }
输出结果和AddressBookUI.framework中的输出结果类似
4)Contacts
1)获取用户的授权
获取授权状态
如果用户是未决定状态,则请求授权
2)获取联系人信息
获取授权状态
如果是已经授权,则获取联系人信息
创建通讯录对象
获取通信录中所有的联系人
遍历所有的联系人,获取联系人信息
获取用户授权的代码实现,通常在应用启动时就询问用户授权,请求授权需要在info.plist配置NSContactsUsageDescription这个key
AppDelegate代码如下所示:
import UIKit
import Contacts @UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // 1.获取授权状态
// CNContactStore --> 通信录对象
let status = CNContactStore.authorizationStatus(for: .contacts) // 2.判断如果是未决定状态,请求授权
if status == .notDetermined {
// 2.1.创建通信录对象
let store = CNContactStore() // 2.2.请求授权
store.requestAccess(for: .contacts, completionHandler: { (isFlag : Bool, error : Error?) in
if isFlag {
print("授权成功")
} else {
print("授权失败")
}
})
} return true
}
}
ViewController中代码如下:
import UIKit
import Contacts class ViewController: UIViewController { override func viewDidLoad() {
super.viewDidLoad()
} override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// 1.获取授权状态
let status = CNContactStore.authorizationStatus(for: .contacts) // 2.判断是否是已经授权
guard status == .authorized else {
return
} // 3.创建通信录对象
let store = CNContactStore() // 4.从通信录中获取所有的联系人
// 4.1.获取fetch,并且指定之后要获取联系人中的什么属性
let keys = [CNContactFamilyNameKey as NSString, CNContactGivenNameKey as NSString, CNContactPhoneNumbersKey as NSString] // 4.2.创建请求对象
let request = CNContactFetchRequest(keysToFetch: keys) // 4.3.遍历所有的联系人
do {
try store.enumerateContacts(with: request, usingBlock: { (contact : CNContact, stop : UnsafeMutablePointer<ObjCBool>) -> Void in
// 1.获取姓名
let lastname = contact.familyName
let firstname = contact.givenName
print(lastname, firstname) // 2.获取电话号码
let phoneNumers = contact.phoneNumbers
for phone in phoneNumers {
print(phone.label ?? "没有Label")
print(phone.value.stringValue)
}
})
} catch {
print(error)
} }
}
iOS中通讯录的开发的更多相关文章
- 玩转iOS开发:iOS中的GCD开发(三)
上一章, 我们了解到了GCD里的一些队列和任务的知识, 也实践了一下, 同时我们也对主队列的一些小情况了解了一下, 比如上一章讲到的卡线程的问题, 如果没有看的朋友可以去看看玩转iOS开发:iOS中的 ...
- IOS中微博正文开发步骤总结
微博正文开发步骤总结 1.新建正文控制器,在点击首页的某一条微博时跳转过去 2.在MainController中设置导航控制器的代理,监听所有导航控制器的跳转 1> 如果即将显示的不是根控制器 ...
- iOS中通讯录电话号码空格问题
今天在读取通讯录的时候,读取到的手机号码格式为* (***) ***-****的,乍看下,数字中间有空格."-".(.)的非数字字符. 然后我就打算替换这些非数字字符,结果替换完, ...
- iOS中的地图和定位
文章摘自http://www.cnblogs.com/kenshincui/p/4125570.html#location 如有侵权,请联系删除. 概览 现在很多社交.电商.团购应用都引入了地图和定 ...
- iOS中获取本地通讯录联系人以及汉字首字母排序
iOS中获取手机通讯录中的联系人信息: /*** 加载本地联系人*/ - (void)loadLocalContacts { //新建一个通讯录类 ABAddressBookRef addressBo ...
- IOS开发数据存储篇—IOS中的几种数据存储方式
IOS开发数据存储篇—IOS中的几种数据存储方式 发表于2016/4/5 21:02:09 421人阅读 分类: 数据存储 在项目开发当中,我们经常会对一些数据进行本地缓存处理.离线缓存的数据一般都 ...
- iOS开发——高级篇——iOS中常见的设计模式(MVC/单例/委托/观察者)
关于设计模式这个问题,在网上也找过一些资料,下面是我自己总结的,分享给大家 如果你刚接触设计模式,我们有好消息告诉你!首先,多亏了Cocoa的构建方式,你已经使用了许多的设计模式以及被鼓励的最佳实践. ...
- iOS开发小技巧--iOS中设置applicationIconBadgeNumber遇到的问题
iOS中设置applicationIconBadgeNumber 在iOS7中直接设置applicationIconBadgeNumber没有问题,但是在iOS8之后设置applicationIcon ...
- 《转》iOS音频视频初级开发
代码改变世界 Posts - 73, Articles - 0, Comments - 1539 Cnblogs Dashboard Logout HOME CONTACT GALLERY RSS ...
随机推荐
- Java IO 操作(一)
(1)File 类的基础用法 // 1.创建 一个file 对象File file = new File("D:\\aaa");// 2.判断此 file 是否是一个文件夹file ...
- 洛谷 P1827 美国血统 American Heritage Label:字符串Water
题目描述 农夫约翰非常认真地对待他的奶牛们的血统.然而他不是一个真正优秀的记帐员.他把他的奶牛 们的家谱作成二叉树,并且把二叉树以更线性的“树的中序遍历”和“树的前序遍历”的符号加以记录而 不是用图形 ...
- pyqt 发射接收信号
翻页控件: 一.定义并发射信号: #!/usr/bin/python # #coding=utf-8 # __author__='' from PyQt4.QtCore import * from P ...
- matlab 求解线性方程组之LU分解
线性代数中的一个核心思想就是矩阵分解,既将一个复杂的矩阵分解为更简单的矩阵的乘积.常见的有如下分解: LU分解:A=LU,A是m×n矩阵,L是m×m下三角矩阵,U是m×n阶梯形矩阵 QR分解: 秩分解 ...
- maven整理——初步
最近用到了maven,查找了很多资料,写这篇博文是为了记录maven的使用学习,也方便自己日后好查找. 在这里引用http://www.cnblogs.com/dcba1112/archive/201 ...
- oracle导出一条二进制数据(二进制,long只能通过dmp导出)
exp jxfoc/JXFOC@ORCL file=d:\dd.dmp tables=(jxfoc.FLIGHT_PLAN_MAKE_LOG,jxfoc.METAR_CONTENT_FOR_MAIL) ...
- python基础之day1
Python 简介 Python是著名的“龟叔”Guido van Rossum在1989年圣诞节期间,为了打发无聊的圣诞节而编写的一个编程语言. Python为我们提供了非常完善的基础代码库,覆盖了 ...
- Python join()函数
今天写python 100例时,有个题目是大致是这样的:已知输入形式是1+3+2+1,要求输出形式为1+1+2+3 一开始思路是将输入的字符串用split()函数划分成数组,在对数组进行排序,再用fo ...
- SharePoint 2010中一些必须知道的限制
最大文件名长度是123个字符. 一个文档库(library)里最多可以存放10000个文档 一个视图(view)里最多显示5000个条目(item) 推荐的单个内容数据库(content databa ...
- android培训机构排名
Android开发行业的热度打开了Android培训领域的市场,我们会发现有很多的Android培训机构都在大势宣传自己的师资.就业情况.教学环境等 ,然而到底要选择哪个呢?令很多的人困惑.2015年 ...