版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.11.12 |
前言
有关通讯录的框架有好几种,包括
AddressBook
、AddressBookUI
、Contacts
和ContactsUI
,这里,iOS9
以后AddressBook、AddressBookUI
就不推荐使用了,但是如果要支持ios8
以及以前的系统还是要用它们两个框架的。ios9以后系统推荐使用Contacts
和ContactsUI
,接下来的几篇我们就详细的解析一下这几个框架。感兴趣的可以看我写的上面几篇。
1. 通讯录相关框架详细解析(一)—— AddressBook框架基本概览
2. 通讯录相关框架详细解析(二)—— AddressBookUI框架基本概览
Contacts框架
1. 基本情况
框架用来访问用户的联系人并格式化本地化联系人信息。
Contacts
框架提供了Swift和Objective-C API来访问用户的联系信息。 由于大多数应用程序在不做任何更改的情况下读取联系人信息,因此此框架针对线程安全的只读使用进行了优化。
2. Working with the User’s Contacts - 使用用户联系人
该框架适用于所有Apple平台,并取代iOS和MacOS中的Address Book
框架。
Contact Objects
联系人类(CNContact)是联系人属性(如联系人姓名,图像或电话号码)的线程安全的不可变值对象。
contact
类就像NSDictionary
一样,它有一个可修改的子类CNMutableContact,可以用来修改联系人属性。 对于可以具有多个值(例如电话号码或电子邮件地址)的联系人属性,将使用CNLabeledValue对象数组。 带标签的value类是线程安全的,不可变的标签和值的元组。 标签向用户描述每个值,允许差异化,例如家庭和工作电话号码。 Contacts
框架提供了一些预定义的标签,您可以创建自己的自定义标签。
// Listing 1 Creating a contact
// import Contacts
// Creating a mutable object to add to the contact
let contact = CNMutableContact()
contact.imageData = NSData() // The profile picture as a NSData object
contact.givenName = "John"
contact.familyName = "Appleseed"
let homeEmail = CNLabeledValue(label:CNLabelHome, value:"john@example.com")
let workEmail = CNLabeledValue(label:CNLabelWork, value:"j.appleseed@icloud.com")
contact.emailAddresses = [homeEmail, workEmail]
contact.phoneNumbers = [CNLabeledValue(
label:CNLabelPhoneNumberiPhone,
value:CNPhoneNumber(stringValue:"(408) 555-0126"))]
let homeAddress = CNMutablePostalAddress()
homeAddress.street = "1 Infinite Loop"
homeAddress.city = "Cupertino"
homeAddress.state = "CA"
homeAddress.postalCode = "95014"
contact.postalAddresses = [CNLabeledValue(label:CNLabelHome, value:homeAddress)]
let birthday = NSDateComponents()
birthday.day = 1
birthday.month = 4
birthday.year = 1988 // You can omit the year value for a yearless birthday
contact.birthday = birthday
// Saving the newly created contact
let store = CNContactStore()
let saveRequest = CNSaveRequest()
saveRequest.addContact(contact, toContainerWithIdentifier:nil)
try! store.executeSaveRequest(saveRequest)
Formatting and Localization
Contacts
框架可帮助您格式化和本地化联系人信息。 例如,您可以正确格式化联系人姓名(使用
CNContactFormatter)或格式化国际邮政地址(使用 CNPostalAddressFormatter)。
// Listing 2 Formatting a name and postal address
// Formatting contact name
let fullName = CNContactFormatter.stringFromContact(contact, style: .FullName)
print(fullName)
// John Appleseed
// Formatting postal address
let postalString = CNPostalAddressFormatter.stringFromPostalAddress(homeAddress)
print(postalString)
// 1 Infinite Loop
// Cupertino
// CA
// 95014
您可以根据设备的当前区域设置显示本地化的对象属性名称和预定义的标签。Contacts
框架中定义的许多对象(例如CNContact
)都包含localizedStringForKey:
方法,该方法使您可以获取Key名称的本地化版本。 另外,CNLabeledValue
类还包括了localizedStringForLabel:
方法,它可以让你获得Contacts
框架中预定义标签的本地化标签。
// Listing 3 Localizing a given name
// device locale is Spanish
let displayName = CNContact.localizedStringForKey(CNContactNicknameKey)
print(displayName)
// alias
let displayLabel = CNLabeledValue.localizedStringForLabel(CNLabelHome)
print(displayLabel)
// casa
Fetching Contacts
您可以使用代表用户的联系人数据库的联系人存储(CNContactStore)
来获取联系人。 contact store
封装了所有的I / O操作,负责获取和保存联系人和组。 由于contact store
方法是同步的,因此建议您在后台线程上使用它们。 如果需要,您可以安全地将不可变的提取结果发送回主线程。
Contacts
框架提供了几种方法来限制从提取返回的联系人,包括预定义的谓词和keysToFetch
属性。
CNContact
提供了用于过滤要获取的联系人的谓词。 例如,要获取名称为“Appleseed”
的联系人,请使用predicateForContactsMatchingName:
并传入Appleseed
。
// Listing 4 Fetching contacts using predicates
let predicate: NSPredicate = CNContact.predicateForContactsMatchingName("Appleseed")
请注意,通用框架和复合谓词不被Contacts
框架支持。
您可以使用keysToFetch
来限制提取的联系人属性。 例如,如果只想获取联系人的给定名称和姓氏,则可以在keysToFetch
数组中指定这些联系人键。
// Listing 5 Fetching contacts using KeysToFetch
let keysToFetch = [CNContactGivenNameKey, CNContactFamilyNameKey]
要使用谓词(predicateForContactsMatchingName :)
和keysToFetch
数组,请使用unifiedContactsMatchingPredicate:keysToFetch:error :
获取联系人。
// Listing 6 Fetching contacts using a predicate and an array of contact attributes
let store = CNContactStore()
let contacts = try store.unifiedContactsMatchingPredicate(CNContact.predicateForContactsMatchingName("Appleseed"), keysToFetch:[CNContactGivenNameKey, CNContactFamilyNameKey])
Contacts
框架还可以对提取的联系人执行操作,例如格式化联系人姓名。 每个操作都需要一组特定的联系人键才能正确执行操作。 这些键被指定为必须包含在keysToFetch
数组中的键描述符对象。 例如,如果您想要获取联系人的电子邮件地址,并且能够格式化联系人的名称(使用CNContactFormatter
),请在keysToFetch
数组中包含CNContactEmailAddressesKey
和descriptorForRequiredKeysForStyle
返回的关键描述符对象。
// Listing 7 Fetching contacts with key descriptors
let keysToFetch = [CNContactEmailAddressesKey, CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName)]
Privacy
用户可以根据每个应用授予或拒绝访问联系人数据。 任何对CNContactStore
的调用都会在用户被要求授予或拒绝访问的同时阻止应用程序。 请注意,仅在第一次请求访问时提示用户; 任何后续的CNContactStore
调用都使用现有的权限。 为了避免让你的应用程序的UI主线程阻塞这个访问,可以使用异步方法requestAccessForEntityType:completionHandler:
或者将CNContactStore
用法分派到后台线程。
重要:在iOS 10.0或之后链接的iOS应用必须在其Info.plist文件中包含它需要访问的数据类型的使用说明密钥,否则将会崩溃。 要特别访问联系人数据,它必须包含
NSContactsUsageDescription
。
Partial Contacts
部分联系人只有部分属性值从contact store
中获取。 所有提取的联系人对象都是部分联系人。 如果您尝试访问未提取的属性值,则会发生异常。 如果您不确定在联系人中提取了哪些密钥,建议您在访问属性值之前检查属性值的可用性。 您可以使用isKeyAvailable:检查单个联系人密钥的可用性,或者是可用可用:检查多个密钥。 如果所需的按键不可用,则重新与他们联系。
// Listing 8 Checking the availability of a key
// Checking if phone number is available for the given contact.
if (contact.isKeyAvailable(CNContactPhoneNumbersKey)) {
print("\(contact.phoneNumbers)")
} else {
//Refetch the keys
let keysToFetch = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey]
let refetchedContact = try store.unifiedContactWithIdentifier(contact.identifier, keysToFetch: keysToFetch)
print("\(refetchedContact.phoneNumbers)")
}
Unified Contacts
代表同一个人的不同账户中的联系人可以自动链接在一起。 链接的联系人在macOS和iOS应用程序中显示为统一联系人。 统一联系人是合并到一个联系人中的一组链接联系人的内存中暂时视图。
默认情况下Contacts
框架返回统一联系人。 每个获取的统一联系人(CNContact)
对象都具有其自己的唯一标识符,该标识符与链接联系人组中的任何个人联系人标识符不同。 统一联系人的重新提取应该使用其标识符来完成。
Saving Contacts
联系人存储(CNContactStore)
也用于保存对Contacts
框架对象的更改。 CNSaveRequest
类启用保存操作,并允许将多个联系人和组的更改批量分配到一个操作中。 将所有对象添加到保存请求后,可以使用contact store
执行该对象,如Listing 9
所示,代码清单如下所示。 执行保存时不要访问保存请求中的对象,因为对象可能会被修改。
注意:
CNSaveRequest
在watchOS中不可用。
// Listing 9 Saving a new contact
// Creating a new contact
let newContact = CNMutableContact()
newContact.givenName = "John"
newContact.familyName = "Appleseed"
// Saving contact
let saveRequest = CNSaveRequest()
saveRequest.addContact(newContact, toContainerWithIdentifier:nil)
try! store.executeSaveRequest(saveRequest)
// Listing 10 Saving a modified contact
let mutableContact = contact.mutableCopy() as! CNMutableContact
let newEmail = CNLabeledValue(label: CNLabelHome, value: "john@example.com")
mutableContact.emailAddresses.append(newEmail)
let saveRequest = CNSaveRequest()
saveRequest.updateContact(mutableContact)
try! store.executeSaveRequest(saveRequest)
Contacts Changed Notifications
保存成功执行后, contact store
会将CNContactStoreDidChangeNotification
通知发送到默认通知中心。 如果您缓存任何Contacts
框架对象,您需要重新获取这些对象,或者通过它们的标识符,或用于最初获取它们的谓词,然后释放缓存的对象。 请注意,缓存的对象是陈旧的,但不是无效的。
Containers and Groups
用户可能在其设备的本地帐户或配置为同步联系人的服务器帐户中有联系人。 每个帐户至少有一个联系人的容器。 联系人只能在一个容器中。
一个组是一个容器内的一组联系人。 并非所有帐户都支持群组,某些帐户支持子群组。 一个iCloud
帐户只有一个容器,可能有许多组,但没有子组。 另一方面,Exchange
帐户不支持组,但可能有多个表示Exchange文件夹的容器。
Contacts框架基本结构
下面我们就看一下Contacts框架的基本结构。
1. Classes
-
- 表示联系人属性的不可变值对象的线程安全类,例如联系人的名字和电话号码。
-
- 定义获取联系人时使用的提取选项的对象。
-
CNContactFormatter
- 为联系人定义不同格式样式的对象。
-
CNContactProperty
- 表示联系人属性的对象。
-
-
CNContactRelation
类定义了一个不可变的值对象,表示与另一个联系人有关的联系人。 这是一个线程安全的类。
-
-
-
CNContactStore
类是一个线程安全的类,可以获取并保存联系人,组和容器。
-
-
-
CNContactsUserDefaults
类定义用于访问联系人的用户默认值的属性。
-
-
CNContactVCardSerialization
-
CNContactVCardSerialization
支持给定的一组联系人的vCard
表示。
-
-
CNContainer
- 一个线程安全的类,它定义了一个表示容器的不可变对象。
-
CNGroup
- 定义表示组的不可变对象的线程安全类。
-
CNInstantMessageAddress
- 定义表示即时消息地址的不可变值对象的线程安全类。
-
CNLabeledValue
- 一个线程安全的类,它定义了一个将联系人属性值与标签结合在一起的不可变值对象,比如与Home,Work或iPhone标签结合的联系人电话号码。
-
CNMutableContact
- 联系人属性的可变值对象,例如联系人的名字和电话号码。
-
CNMutableGroup
- 表示联系人组的可变值对象。
-
CNMutable<wbr>Postal<wbr>Address
- 联系人的邮政地址的可变表示。
-
CNPhoneNumber
- 一个线程安全的类,它定义了一个代表联系人电话号码的不可变值对象。
-
CNPostalAddress
- 联系人的邮政地址的不可变表示。
-
CNPostalAddressFormatter
- 在联系人中格式化邮政地址的类。
-
CNSaveRequest
- 联系人的保存请求操作。
-
CNSocialProfile
- 一个线程安全的类,它定义了一个代表社交信息的不可变对象。
2. Reference
后记
未完,待续~~~