iOS9 Day-by-Day :: Day 7 :: Contacts Framework

原文地址

這是一個(gè)系列文章,查看更多請(qǐng)移步目錄頁(yè)

iOS 9 中,蘋果介紹了新的 Contacts framework柄粹。允許用戶使用 Objective-C 的 API 和設(shè)備的通訊錄進(jìn)行交互,同樣適用于 Swift 語(yǔ)言。比起之前通過 AddressBook framework 來(lái)讀取聯(lián)系人信息來(lái)說芋绸,這是一個(gè)巨大的進(jìn)步。因?yàn)?AddressBook framework 沒有 Objective-C 的 API担敌,非常難用摔敛,用 Swift 寫的時(shí)候更是痛苦。希望新的 Contacts framework 能夠解決這些痛點(diǎn)全封。

開發(fā)者有多不喜歡 AddressBook framework 呢马昙?我想在 WWDC 的相關(guān) session 里,當(dāng)宣布 AddressBook framework 會(huì)在 iOS 9 中棄用后刹悴,現(xiàn)場(chǎng)爆發(fā)了最長(zhǎng)時(shí)間行楞、最大聲的歡呼,就是最好的證明土匀。

從 Framework 中返回的聯(lián)系人是統(tǒng)一的子房,這意味著,如果你有從不同的數(shù)據(jù)源來(lái)的相同聯(lián)系人數(shù)據(jù)就轧,他們會(huì)自動(dòng)合并证杭,無(wú)需手動(dòng)進(jìn)行合并的操作。

使用新的 Contacts Framework

現(xiàn)在我們來(lái)創(chuàng)建一個(gè)簡(jiǎn)單的應(yīng)用钓丰。這個(gè)應(yīng)用展示一個(gè)你的通訊錄的聯(lián)系人列表躯砰,同時(shí)允許你查看(聯(lián)系人的)詳細(xì)信息。


contact result

如果你所見携丁,這是一個(gè) master detail view controller 應(yīng)用琢歇,在 iPhone 同樣可以很好的展示。在左邊是一個(gè)你的設(shè)備上的聯(lián)系人列表梦鉴,右邊可以看到聯(lián)系人的頭像李茫、姓名、電話號(hào)碼等詳細(xì)信息肥橙。

獲取用戶的聯(lián)系人

用Xcode 新建一個(gè)項(xiàng)目魄宏,只需要選擇 master detail view controller 模版就可以開始了。他會(huì)給你設(shè)置好存筏。

創(chuàng)建好項(xiàng)目后宠互,打開 MasterViewController 類味榛,首先我們要在頭部引入 Contacts 和 ContactsUI 框架。

import Contacts

import ContactsUI

現(xiàn)在我們寫一個(gè)方法予跌,填充 datasrouce的特性搏色。這個(gè)方法要讀取和展示當(dāng)前設(shè)備通訊錄里的聯(lián)系人。

func findContacts() -> [CNContact] {

let store = CNContactStore()

CNContactStore 是一個(gè)用來(lái)讀取和保存聯(lián)系人的新的類券册。這篇文章中我們僅僅展示如何讀取聯(lián)系人频轿,但是你同樣可以(用此方法)進(jìn)行展示和保存聯(lián)系人群組操作。

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

CNContactImageDataKey,

CNContactPhoneNumbersKey]

let fetchRequest = CNContactFetchRequest(keysToFetch: keysToFetch)

當(dāng)我們有了這個(gè)聯(lián)系人數(shù)據(jù)庫(kù)的引用后烁焙,我們需要?jiǎng)?chuàng)建一個(gè)指定條件的請(qǐng)求航邢,通過這個(gè) query 的請(qǐng)求去獲取某些結(jié)果。創(chuàng)建一個(gè) CNContactFetchRequest 骄蝇,我們可以通過設(shè)置 contact keys 的數(shù)組膳殷,來(lái)獲取我們需要的結(jié)果。有趣的是九火,我們可以通過CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName) 來(lái)格式化秽之。這是CNContactFormattter 的一個(gè)非常方便的方法,稍后我們還會(huì)用到吃既。

CNContactFormatter 需要很多不同的 keys考榨,如果不使用 descriptorForRequiredKeysForStyle 方法,我們需要手動(dòng)設(shè)置以下的 keys鹦倚。

[CNContactGivenNameKey,

CNContactNamePrefixKey,

CNContactNameSuffixKey,

CNContactMiddleNameKey,

CNContactFamilyNameKey,

CNContactTypeKey...]

如你所見河质,要寫一大堆代碼。當(dāng) CNContactFormatter key 的需求發(fā)生改變震叙,在從CNContactFormatter 生成一個(gè)字符串時(shí)掀鹅,你會(huì)接到一個(gè)異常。

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

這段代碼非常簡(jiǎn)單媒楼。我們所做的是從 CNContactStore 中遍歷所有符合我們需求的聯(lián)系人乐尊。這個(gè)request 沒有加任何的條件,所以會(huì)返回全部的聯(lián)系人划址,包含我們需要的 keys扔嵌。我們把每一條記錄都逐個(gè)保存到一個(gè)數(shù)組中,返回夺颤。

現(xiàn)在我們要調(diào)用這個(gè)方法痢缎,用表格來(lái)展示結(jié)果。再次打開 MasterViewController世澜, 添加一個(gè)屬性独旷,用來(lái)展示結(jié)果。

var contacts = [CNContact]()

更新 viewDidLoad 方法,用同步的方法調(diào)用并存儲(chǔ)結(jié)果嵌洼。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {

? ? self.contacts = self.findContacts()

? ? dispatch_async(dispatch_get_main_queue()) {

? ? ? ? self.tableView!.reloadData()

? ? }

}


一旦保存好結(jié)果案疲,刷新表格。

你需要修改一下 UITableViewDatasource 的方法來(lái)展示剛剛得到的結(jié)果麻养。

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

? ? return self.contacts.count

}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

? ? let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)

? ? let contact = contacts[indexPath.row] as CNContact

? ? cell.textLabel!.text = "\(contact.givenName) \(contact.familyName)"

? ? return cell

}

現(xiàn)在剩下的就是在 DetailViewController 中展示聯(lián)系人的詳細(xì)信息了络拌。這里我不在細(xì)述,你需要在 DetailViewController 中添加一個(gè)圖像視圖回溺、兩個(gè)標(biāo)簽視圖,來(lái)展示頭像混萝、姓名和電話號(hào)碼遗遵。并且在 interface builder 中創(chuàng)建 IBOutlet.

@IBOutlet weak var contactImageView: UIImageView!

@IBOutlet weak var contactNameLabel: UILabel!

@IBOutlet weak var contactPhoneNumberLabel: UILabel!

當(dāng)這些做完,我們需要設(shè)置當(dāng)前的值逸嘀。在 configureView 车要,你需要添加下面這行代碼。

label.text = CNContactFormatter.stringFromContact(contact, style: .FullName)

正如我們之前提到的崭倘,CNContactFormatter 能夠很好的格式化聯(lián)系人的名字翼岁。我們所要做的僅僅是按需求格式化他們,formatter可以很好的控制格式司光。

在設(shè)置頭像時(shí)琅坡,我們需要先檢測(cè)一下 imageData 是否存在。如果設(shè)備上的某個(gè)聯(lián)系人沒有設(shè)置頭像残家, imageData 可能沒有榆俺,(不檢測(cè)的話)應(yīng)用會(huì)崩潰。

if contact.imageData != nil {

? ? imageView.image = UIImage(data: contact.imageData!)

}?else {

? ? imageView.image = nil

}

如果存在坞淮,我們給 image view 設(shè)置好茴晋。

最后,我們給電話號(hào)碼標(biāo)簽指定值回窘。

if let phoneNumberLabel = self.contactPhoneNumberLabel {

? ? var numberArray = [String]()

? ? for number in contact.phoneNumbers {

? ? ? ? let phoneNumber = number.value as! CNPhoneNumber

? ? ? ? numberArray.append(phoneNumber.stringValue)

? ? }

? ? phoneNumberLabel.text = ", ".join(numberArray)

}

這是最終的展示結(jié)果∨瞪茫現(xiàn)在,我們擁有一個(gè)app啡直,可以在左側(cè)烁涌,顯示設(shè)備上通訊錄中聯(lián)系人的列表,并可以逐個(gè)找到他的詳細(xì)信息酒觅。


contact details

使用 ContactsUI 選擇聯(lián)系人

也許我們希望這個(gè)應(yīng)用烹玉,可以讓用戶自己選擇聯(lián)系人,并且展示詳細(xì)信息給我們阐滩。正如此前你看到的二打,這可能要寫很多代碼。如果這些功能已經(jīng)做好了的掂榔,會(huì)讓開發(fā)變的更加簡(jiǎn)單继效。

這正是 ContactsUI framework 的功能症杏。他提供了一套 view controllers,我們可以用在我們的應(yīng)用中瑞信,展示聯(lián)系人的信息厉颤。

在這一節(jié),我們想讓用戶可以選擇某個(gè)電話號(hào)碼凡简,并且保存起來(lái)逼友。因?yàn)橹皇且粋€(gè) demo,所以我們選擇在 MasterViewController 的右上角添加一個(gè) UIBarButtonItem秤涩,然后在 MasterViewController 類中帜乞,給 UIBarButtonItem 一個(gè)方法。

@IBAction func showContactsPicker(sender: UIBarButtonItem) {

? ? let contactPicker = CNContactPickerViewController()

? ? contactPicker.delegate = self;

? ? contactPicker.displayedPropertyKeys = [CNContactPhoneNumbersKey]

? ? self.presentViewController(contactPicker, animated: true, completion: nil)

}

我們創(chuàng)建了一個(gè)簡(jiǎn)單的 CNContactPickerViewController 筐眷,設(shè)置他的代理為 self.這樣我們就能夠響應(yīng)他的請(qǐng)求黎烈,我們感興趣的事電話號(hào)碼,盡在選中電話號(hào)碼后匀谣,展示聯(lián)系人信息照棋。CNContactPickerViewController 幫我們控制UI。

func contactPicker(picker: CNContactPickerViewController, didSelectContactProperty contactProperty: CNContactProperty) {

? ? let contact = contactProperty.contact

? ? let phoneNumber = contactProperty.value as! CNPhoneNumber

? ? print(contact.givenName)

? ? print(phoneNumber.stringValue)

}

在 contactPicker 代理方法 didSelectContactProperty 中武翎,我們復(fù)制一個(gè)CNContactProperty 對(duì)象烈炭。這是 CNContact 的一個(gè) wrapper。讓我們來(lái)看一下他是怎么工作的宝恶。


contact picker

當(dāng)我們點(diǎn)擊 MasterViewController 右上角的 UIBarButtonItem 后梳庆,會(huì)展示一個(gè)頁(yè)面。這個(gè)頁(yè)面是所有聯(lián)系人的列表卑惜,我們沒有添加任何的過濾條件膏执。


contact selected

當(dāng)你點(diǎn)擊某個(gè)聯(lián)系人,會(huì)展示出這個(gè)聯(lián)系人的電話列表露久。正是我們之前CNContactPhoneNumbersKey 里設(shè)置的一樣更米,這個(gè)頁(yè)面僅展示了我們需要的關(guān)鍵字段。

最后毫痕,當(dāng)你點(diǎn)擊了頁(yè)面中某些屬性征峦,例如電話號(hào)碼后,會(huì)在 picker 關(guān)閉前觸發(fā) contactPicker:didSelectContactProperty方法消请。

在這個(gè)例子中栏笆,名字叫“Kate Bell”的聯(lián)系人是 CNContact 的一個(gè)例子‰“phoneNumbers”是 key蛉加,“5555648583”是 CNPhoneNumber 的值。最后 identifier 字符串作為他的 identifier property.

總結(jié)一下,這個(gè)例子里我們使用 ContactsUI framework 來(lái)展示選取某個(gè)聯(lián)系人针饥,是多么簡(jiǎn)單和易用厂抽。如果你想開發(fā)更加豐富的頁(yè)面,更自主的控制頁(yè)面的展示信息丁眼,Contacts framework 會(huì)給你提供很好的獲取數(shù)據(jù)信息的方式筷凤。

延伸閱讀

更多關(guān)于 Contacts Framework 的信息,我推薦你觀看WWDC 2015 的 session 223 Introducing the Contacts Framework for iOS and OS X. 最后不要忘了苞七,你可以在 Github 上找到我們已經(jīng)創(chuàng)建的本篇文章的Demo項(xiàng)目藐守。

這是一個(gè)系列文章,查看更多請(qǐng)移步目錄頁(yè)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蹂风,一起剝皮案震驚了整個(gè)濱河市卢厂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌硫眨,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巢块,死亡現(xiàn)場(chǎng)離奇詭異礁阁,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)族奢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門姥闭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人越走,你說我怎么就攤上這事棚品。” “怎么了廊敌?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵铜跑,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我骡澈,道長(zhǎng)锅纺,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任肋殴,我火速辦了婚禮囤锉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘护锤。我一直安慰自己官地,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布烙懦。 她就那樣靜靜地躺著驱入,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沧侥,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天可霎,我揣著相機(jī)與錄音,去河邊找鬼宴杀。 笑死癣朗,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的旺罢。 我是一名探鬼主播旷余,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼扁达!你這毒婦竟也來(lái)了正卧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤跪解,失蹤者是張志新(化名)和其女友劉穎炉旷,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體叉讥,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡窘行,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了图仓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罐盔。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖救崔,靈堂內(nèi)的尸體忽然破棺而出惶看,到底是詐尸還是另有隱情,我是刑警寧澤六孵,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布纬黎,位于F島的核電站,受9級(jí)特大地震影響劫窒,放射性物質(zhì)發(fā)生泄漏莹桅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一烛亦、第九天 我趴在偏房一處隱蔽的房頂上張望诈泼。 院中可真熱鬧,春花似錦煤禽、人聲如沸铐达。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瓮孙。三九已至唐断,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間杭抠,已是汗流浹背脸甘。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留偏灿,地道東北人丹诀。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像翁垂,于是被迫代替她去往敵國(guó)和親铆遭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容