iOS 9 中,苹果介绍了新的 Contacts framework。允许用户使用 Objective-C 的 API 和设备的通讯录进行交互,同样适用于 Swift 语言。比起之前通过 AddressBook framework 来读取联系人信息来说,这是一个巨大的进步。因为 AddressBook framework 没有 Objective-C 的 API,非常难用,用 Swift 写的时候更是痛苦。希望新的 Contacts framework 能够解决这些痛点。
开发者有多不喜欢 AddressBook framework 呢?我想在 WWDC 的相关 session 里,当宣布 AddressBook framework 会在 iOS 9 中弃用后,现场爆发了最长时间、最大声的欢呼,就是最好的证明。
从 Framework 中返回的联系人是统一的,这意味着,如果你有从不同的数据源来的相同联系人数据,他们会自动合并,无需手动进行合并的操作。
使用新的 Contacts Framework
现在我们来创建一个简单的应用。这个应用展示一个你的通讯录的联系人列表,同时允许你查看(联系人的)详细信息。
contact result
如果你所见,这是一个 master detail view controller 应用,在 iPhone 同样可以很好的展示。在左边是一个你的设备上的联系人列表,右边可以看到联系人的头像、姓名、电话号码等详细信息。
获取用户的联系人
用Xcode 新建一个项目,只需要选择 master detail view controller 模版就可以开始了。他会给你设置好。
创建好项目后,打开 MasterViewController 类,首先我们要在头部引入 Contacts 和 ContactsUI 框架。
1 2 |
import Contacts import ContactsUI |
现在我们写一个方法,填充 datasrouce的特性。这个方法要读取和展示当前设备通讯录里的联系人。
1 2 |
func findContacts() -> [CNContact] { let store = CNContactStore() |
CNContactStore 是一个用来读取和保存联系人的新的类。这篇文章中我们仅仅展示如何读取联系人,但是你同样可以(用此方法)进行展示和保存联系人群组操作。
1 2 3 4 |
let keysToFetch = [CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName), CNContactImageDataKey, CNContactPhoneNumbersKey] let fetchRequest = CNContactFetchRequest(keysToFetch: keysToFetch) |
当我们有了这个联系人数据库的引用后,我们需要创建一个指定条件的请求,通过这个 query 的请求去获取某些结果。创建一个 CNContactFetchRequest ,我们可以通过设置 contact keys 的数组,来获取我们需要的结果。有趣的是,我们可以通过CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName) 来格式化。这是CNContactFormattter 的一个非常方便的方法,稍后我们还会用到。
CNContactFormatter 需要很多不同的 keys,如果不使用 descriptorForRequiredKeysForStyle 方法,我们需要手动设置以下的 keys。
[CNContactGivenNameKey,
CNContactNamePrefixKey,
CNContactNameSuffixKey,
CNContactMiddleNameKey,
CNContactFamilyNameKey,
CNContactTypeKey…]
如你所见,要写一大堆代码。当 CNContactFormatter key 的需求发生改变,在从CNContactFormatter 生成一个字符串时,你会接到一个异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
var contacts = [CNContact]() do { try store.enumerateContactsWithFetchRequest(fetchRequest, usingBlock: { (let contact, let stop) -> Void in contacts.append(contact) }) } catch let error as NSError { print(error.localizedDescription) } return contacts |
这段代码非常简单。我们所做的是从 CNContactStore 中遍历所有符合我们需求的联系人。这个request 没有加任何的条件,所以会返回全部的联系人,包含我们需要的 keys。我们把每一条记录都逐个保存到一个数组中,返回。
现在我们要调用这个方法,用表格来展示结果。再次打开 MasterViewController, 添加一个属性,用来展示结果。
1 |
var contacts = [CNContact]() |
更新 viewDidLoad 方法,用同步的方法调用并存储结果。
1 2 3 4 5 6 7 8 9 10 |
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { self.contacts = self.findContacts() dispatch_async(dispatch_get_main_queue()) { self.tableView!.reloadData() } } |
一旦保存好结果,刷新表格。
你需要修改一下 UITableViewDatasource 的方法来展示刚刚得到的结果。
1 2 3 |
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{ return self.contacts.count } |
开发者有多不喜欢 AddressBook framework 呢?我想在 WWDC 的相关 session 里,当宣布 AddressBook framework 会在 iOS 9 中弃用后,现场爆发了最长时间、最大声的欢呼,就是最好的证明。
从 Framework 中返回的联系人是统一的,这意味着,如果你有从不同的数据源来的相同联系人数据,他们会自动合并,无需手动进行合并的操作。
使用新的 Contacts Framework
现在我们来创建一个简单的应用。这个应用展示一个你的通讯录的联系人列表,同时允许你查看(联系人的)详细信息。
contact result
如果你所见,这是一个 master detail view controller 应用,在 iPhone 同样可以很好的展示。在左边是一个你的设备上的联系人列表,右边可以看到联系人的头像、姓名、电话号码等详细信息。
获取用户的联系人
用Xcode 新建一个项目,只需要选择 master detail view controller 模版就可以开始了。他会给你设置好。
创建好项目后,打开 MasterViewController 类,首先我们要在头部引入 Contacts 和 ContactsUI 框架。
1 2 |
import Contacts import ContactsUI |
现在我们写一个方法,填充 datasrouce的特性。这个方法要读取和展示当前设备通讯录里的联系人。
1 2 |
func findContacts() -> [CNContact] { let store = CNContactStore() |
CNContactStore 是一个用来读取和保存联系人的新的类。这篇文章中我们仅仅展示如何读取联系人,但是你同样可以(用此方法)进行展示和保存联系人群组操作。
1 2 3 4 |
let keysToFetch = [CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName), CNContactImageDataKey, CNContactPhoneNumbersKey] let fetchRequest = CNContactFetchRequest(keysToFetch: keysToFetch) |
当我们有了这个联系人数据库的引用后,我们需要创建一个指定条件的请求,通过这个 query 的请求去获取某些结果。创建一个 CNContactFetchRequest ,我们可以通过设置 contact keys 的数组,来获取我们需要的结果。有趣的是,我们可以通过CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName) 来格式化。这是CNContactFormattter 的一个非常方便的方法,稍后我们还会用到。
CNContactFormatter 需要很多不同的 keys,如果不使用 descriptorForRequiredKeysForStyle 方法,我们需要手动设置以下的 keys。
[CNContactGivenNameKey,
CNContactNamePrefixKey,
CNContactNameSuffixKey,
CNContactMiddleNameKey,
CNContactFamilyNameKey,
CNContactTypeKey…]
如你所见,要写一大堆代码。当 CNContactFormatter key 的需求发生改变,在从CNContactFormatter 生成一个字符串时,你会接到一个异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
var contacts = [CNContact]() do { try store.enumerateContactsWithFetchRequest(fetchRequest, usingBlock: { (let contact, let stop) -> Void in contacts.append(contact) }) } catch let error as NSError { print(error.localizedDescription) } return contacts |
这段代码非常简单。我们所做的是从 CNContactStore 中遍历所有符合我们需求的联系人。这个request 没有加任何的条件,所以会返回全部的联系人,包含我们需要的 keys。我们把每一条记录都逐个保存到一个数组中,返回。
现在我们要调用这个方法,用表格来展示结果。再次打开 MasterViewController, 添加一个属性,用来展示结果。
1 |
var contacts = [CNContact]() |
更新 viewDidLoad 方法,用同步的方法调用并存储结果。
1 2 3 4 5 6 7 8 9 10 |
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { self.contacts = self.findContacts() dispatch_async(dispatch_get_main_queue()) { self.tableView!.reloadData() } } |
一旦保存好结果,刷新表格。
你需要修改一下 UITableViewDatasource 的方法来展示刚刚得到的结果。
1 2 3 |
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{ return self.contacts.count } |