iOS9 Contacts Framework简介

这个全新的联系人框架,简单易用,使用它可以很容易地查找、创建和更新联系人信息,而且这个framework对thred-safe、read-only usage方面进行了优化。iOS和OS X平台都可用,用来代替之前的AddressBook framework。
翻译自官方文档Contacts Framework Reference

联系人对象

CNContact表示一条联系人记录,包含联系人的name、image、phone numbers.
这个类像NSDictionary一样;拥有一个可变的子类CNMutableContact,你可以使用它修改联系人属性。而这些属性可以拥有多个值,例如phone numbers或者email addresses,这些就是一组CNLabeledValue对象的数组。这个labeled value对象是线程安全的,由不可变labels和values的元组组成。Contacts framework提供一些预先定义的labels,你也可以创建自定义的labels。

创建一个联系人:

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)

格式和本地化

Contacts framework可以帮助你格式和本地化联系人信息。例如,你可以准确无误地格式一个联系人name(使用CNContactFormatter),或者格式一个国际邮政地址(使用CNPostalAddressFormatter)

格式联系人name和邮政地址

// 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

你可以通过设备当前的本地设置本地化展示对象的names属性和预先设定的labels。
CNContact类包含localizedStringForKey:方法,它可以通过key值获取本地化的译本。而CNLabeledValue类包含localizedStringForLabel:方法,它可以通过预先设定的labels获取本地化的label,从而获取相应的信息。

本地化的name:

// device locale is Spanish
let displayName = CNContact.localizedStringForKey(CNContactNicknameKey)
print(displayName)
// alias
 
let displayLabel = CNLabeledValue.localizedStringForLabel(CNLabelHome)
print(displayLabel)
// casa

获取联系人

你可以使用联系人仓库(CNContactStore),也就是用户联系人的数据库来获取联系人。联系人数据库的方法是同步的,这就需要你在后台线程使用它们。而后在主线程中返回获取到的结果。

Contacts framework提供几种方法检索联系人,包括predicates和keysToFetch

通过predicates获取联系人:

let predicate: NSPredicate = CNContact.predicateForContactsMatchingName("Appleseed")

通过KeysToFetch获取联系人:

let keysToFetch = [CNContactGivenNameKey,CNContactFamilyNameKey]

如何获取联系人:

let store = CNContactStore()
let contacts = try store.unifiedContactsMatchingPredicate(CNContact.predicateForContactsMatchingName("Appleseed"), keysToFetch:[CNContactGivenNameKey, CNContactFamilyNameKey])

Contacts framework也可以在获取到的联系人上执行操作,例如格式联系人name。每次执行操作都需要特定的keys来保证其准确无误。这些keys是特定的key描述对象,包含在keysToFetch之内。

通过key值描述获取联系人:

let keysToFetch = [CNContactEmailAddressesKey, CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName)]

隐私

用户可以允许或者拒绝访问联系人数据。其中为了避免APP UI的主线程获取,你要么使用异步方法[CNContactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:],要么派遣你的CNContactStore内存到后台线程。

局部联系人

一个局部联系人仅仅只有一些从联系人数据库获取来的属性值。所有获取到的联系人对象都是局部联系人。如果你使用一个没有获取到的属性值,将会抛出异常。如果你不确定keys在联系人中是否被获取到,在使用它们之前最好先检查其可用性。你可以使用isKeyAvailable:去检查单个联系人key的可用性,也可以使用areKeysAvailable:去检查多个keys。如果检查的keys不可用就需要重新获取。

使用isKeyAvailable检查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)")
}

整合联系人

每一个获取的整合联系人(CNContact)对象都有它自己独一无二的标识符,它与其他一连串联系人的标识符都不同。重新获取一个整合的联系人应该通过它的标识符来完成。

保存联系人

CNSaveRequest类可以实现保存操作而且允许批量修改多个联系人和分组。
注意:不要在save request中使用正在执行保存的对象,因为它可能已经被修改。

保存一个新的联系人:

// 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)

保存一个修改的联系人:

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)

联系人被改变通知

在save执行成功之后,联系人数据库提交一个CNContactStoreDidChangeNotification通知到通知者中心。如果你缓存了所有的联系人对象,你需要重新获取它们,要么使用它们的标识符,要么通过最初获取的predicates来重新获取,而且你需要释放掉缓存的对象。注意缓存的对象是旧的但不一定是无效的。

容器和群组

用户可以同步本地设备的联系人和服务器的联系人。每个账户至少有一个联系人容器,一个联系人也只能出现在一个容器里面。

一系列联系人组成的群组在一个容器里面。不是所有账户都支持群组,一些账户可能支持子群。一个iCloud账户只有一个容器,它可以有很多群组但没有子群。

类组成

  • CNContact:表示一个联系人,包含联系人的name、image、phone numbers,不可变;
  • CNMutableContact:CNContact的子类,表示具有可变属性的联系人;
  • CNContactFetchRequest:用于获取联系人;
  • CNContactProperty:关于联系人的property的类,含有contact、key、value、label以及identifier;
  • CNContactRelation:表示一个联系人与另一个关系的不可变值对象;
  • CNContactStore:联系人仓库,可以获取、保存联系人,与群组、容器有关;
  • CNContactVCardSerialization:提供vCard表示给定的一系列的联系人;
  • CNContactsUserDefaults:联系人user defaults使用过的properties;
  • CNContainer:联系人容器,不可变;
  • CNGroup:联系人群组,不可变;
  • CNMutableGroup:CNGroup的子类,表示可变的联系人群组;
  • CNInstantMessageAddress:表示一个当前消息地址;
  • CNLabeledValue:联合一个label的联系人属性值;
  • CNPhoneNumber:表示一个联系人的phone number;
  • CNPostalAddress:表示一个联系人的邮政地址;
  • CNMutablePostalAddress:CNPostalAddress的子类,表示可变的联系人邮政地址;
  • CNSaveRequest:表示一个联系人保存操作请求;
  • CNSocialProfile:表示社会简况;
  • CNContactFormatter:NSFormatter的子类,定义不同的联系人格式风格;
  • CNPostalAddressFormatter:联系人邮政地址格式;

扩展

如果想了解更多关于Contacts Framwork的信息,推荐观看WWDC2015大会上的视频Introducing the Contacts Framework for iOS and OS X

初始iOS9中新的联系人框架:

  • 检查应用是否准许访问联系人,并且如何请求授权。
  • 使用三种不同的方式检索联系人。其中一种方式将会涉及 Picker View Controller 的使用。
  • 访问检索到的联系人属性,并调整为适当的显示格式。
  • 使用默认的 Contacts UI 来实现选择、查看以及编辑联系人。
  • 创建一个新的联系人
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,614评论 4 59
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 方法一.使用Qt自带的windeployqt.exe 打包工具方法二.使用下面链接的打包工具链接:http://p...
    Noefl阅读 261评论 0 0
  • 六天的新疆之旅即将结束了 在这里我们走过了天池 走过了那拉提 走过了巴音布鲁克 最美的风景还是在那拉提 一望无际的...
    亲爱的琉小璃阅读 163评论 0 1
  • 这个世界很繁华, 小镇没有树, 鸟儿没有家。
    美人驴儿阅读 193评论 3 3