iOS 9: Day by Day 第七天 Contacts框架

本文翻譯自Chris Grant《iOS9 Day-by-Day :: Day 7 :: Contacts Framework》(https://www.shinobicontrols.com/blog/ios9-day-by-day-day7-contacts-framework)佩伤。感謝Chris Grant的辛苦工作沿猜!

iOS 9引入了一個新的聯(lián)系人框架(Contact)。通過這個框架膘盖,我們可以使用Objective-C或者Swift API訪問設(shè)備的通訊錄。這比之前通過AddressBook框架進行訪問改進了不少斤蔓。AddressBook框架沒有提供Objective-C接口孵滞,引起使用起來非常復(fù)雜。而對于Swift用戶來說遏餐,這真是解決了一大痛點。

WWDC上宣布在iOS 9里廢棄AddressBook后的歡呼聲說明了開發(fā)者有多么痛恨這個框架赢底。

使用該框架所獲取的聯(lián)系人都是唯一的失都,因此我們不需要擔心從不同來源復(fù)制數(shù)據(jù)的時候,會產(chǎn)生重復(fù)內(nèi)容幸冻。事實上粹庞,它們會被合并在一起再呈現(xiàn)給我們。因此并不需要我們手動的合并聯(lián)系人信息嘁扼。

使用新的聯(lián)系人框架

下面我們將構(gòu)建一個簡單的應(yīng)用程序來展示通訊錄信粮,并且允許查看聯(lián)系人詳情。

可以看到趁啸,我們使用的是Master-Detail應(yīng)用程序强缘,它同樣可以在iPhone上運行督惰。左側(cè)顯示通訊錄,而右側(cè)顯示選中的聯(lián)系人的圖片旅掂、姓名赏胚、電話等詳細信息。

獲取用戶的通訊錄

使用Xcode的Master-Detail模板創(chuàng)建一個應(yīng)用程序商虐。打開MasterViewController觉阅,用import引入ContactsContactsUI框架。

import Contacts
import ContactsUI

替換默認的數(shù)據(jù)源行為秘车,其中一個用于獲取數(shù)據(jù)典勇,另外一個用于顯示當前聯(lián)系人信息。

func findContacts() -> [CNContact] {
    let store = CNContactStore()
}

CNContactStore可以用于獲取和保存聯(lián)系人叮趴。雖然它可以被用來存取聯(lián)系人組割笙,但本文只會使用它來訪問聯(lián)系人信息。

let keysToFetch = [CNContactFormatter.descriptorForRequredKeysForStyle(.FullName), CNContactImageDataKey, CNContactPhoneNumbersKey]

let fetchRequest = CNContactFetchRequest(keysToFetch: keysToFetch)

一旦獲取了存儲對象(Store)眯亦,就可以通過請求對象(Fetch Request)進行查詢伤溉。創(chuàng)建CNContactFetchRequest需要通過數(shù)組說明請求的字段。其中有意思的一個是CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName)妻率。它是CNContactFormatter的一個快捷方法乱顾。如果沒有這個方法的話,CNContactFormatter需要手動指定多個不同的Key:

[CNContactGivenNameKey,
 CNContactNamePrefixKey,
 CNContactNameSuffixKey,
 CNContactMiddleNameKey,
 CNContactFamilyNameKey,
 CNContactTypeKey...]

不但需要代碼量較多宫静,而且以后有可能發(fā)生變化走净。

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獲取通訊錄的代碼非常簡單囊嘉。這個請求對象并沒有明確過濾條件温技,因此會返回所有的聯(lián)系人革为。

接下來就只要在MasterViewController中增加一個屬性來保存所獲取到的信息扭粱。

var contacts = [CNContact]()

然后在viewDidLoad中更新UITableView(異步)。

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的幾個方法進行修改:

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
}

接下來就是修改DetailViewController來顯示聯(lián)系人詳情震檩。這里我們不會深入討論怎么實現(xiàn)琢蛤,而只在界面上添加一個圖片視圖和兩個分別顯示姓名和電話號碼的標簽,并與DetailViewController建立IBOutlet連接抛虏。

@IBOutlet weak var contactImageView: UIImageView!
@IBOutlet weak var contactNameLabel: UILabel!
@IBOutlet weak var contactPhoneNumberLabel: UILabel!

一旦完成UI的設(shè)計博其,我們就可以給它們設(shè)置正確的值。下面是CNContact對象的使用方法迂猴。在configureView方法中添加以下代碼:

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

根據(jù)上面的討論慕淡,CNContactFormatter可以獲取指定格式的聯(lián)系人姓名字符串。在顯示頭像之前沸毁,需要檢查是否設(shè)置了頭像峰髓。imageData是Optional類型的變量傻寂,如果沒有設(shè)置頭像,可能會導(dǎo)致程序崩潰携兵。

if contact.imageData != nil {
    imageView.image = UIImage(data: contact.imageData!)
}
else {
    imageView.image = nil
}

如果存在頭像疾掰,使用它創(chuàng)建一個UIImage對象,并顯示在UIImageView上徐紧。最后就是顯示電話號碼的代碼:

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

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

如果我們希望用戶可以選取聯(lián)系人并在程序中使用静檬。上面的做法需要編寫大量代碼來手動獲取信息和顯示UI。實際上還有一種更簡單的方式來做這件事情并级。iOS 9給我們提供了ContactsUI框架拂檩。它有一組可以顯示聯(lián)系人信息的視圖控制器。

在這一節(jié)中嘲碧,我們想要用戶能夠選取一個電話號碼广恢,并記錄在程序中。由于這只是一個簡單的示例呀潭,我們在MasterViewController的導(dǎo)航條右側(cè)增加一個UIBarButtonItem作為入口钉迷。這個按鈕關(guān)聯(lián)的MasterViewController中方法如下:

@IBAction func showContactsPicker(sender: UIBarButtonItem) {
    let contactPicker = CNContactPickerViewController()
    contactPicker.delegate = self;
    contactPicker.displayedPropertyKeys = [CNContactPhoneNumbersKey]

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

我們創(chuàng)建了一個新的CNContactPickerViewController并設(shè)置代理。這樣我們就可以獲取用戶響應(yīng)钠署,并指定只獲取電話號碼糠聪,然后顯示視圖控制器。

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中谐鼎,我們得到一個CNContactProperty對象舰蟆。它封裝了一個CNContact對象以及感興趣的屬性。

點擊MasterViewController右上角的UIBarButtonItem后狸棍,就會顯示上圖的界面身害。由于我們沒有給CNContactPickerViewController添加過濾器,因此它會列出所有的聯(lián)系人草戈。

一旦選取一個聯(lián)系人塌鸯,就會得到他的所有電話號碼,但是并不會顯示其它信息唐片。最后丙猬,如果選中其中一個屬性,比如上圖中的電話號碼费韭,就會調(diào)用contactPicker:didSelectContactProperty并回到上一個頁面茧球。

這樣我們就拿到了對應(yīng)聯(lián)系人“Kate Bell”的CNContact對象以及“phoneNumber”,其中“5555648583”是電話號碼星持。

總而言之抢埋,使用ContactsUI框架來選取聯(lián)系人信息非常簡單。我們我們需要更靈活的操作聯(lián)系人,就需要使用Contacts框架的功能揪垄。

更多信息

請觀看WWDC session 223:“Introducing the Contacts Framework for iOS and OS X”鲤屡。別忘了我們的示例代碼在GitHub上。

戴維營教育

戴維營教育(Dive In Education)福侈,潛心做IT職業(yè)教育酒来!緊跟時代潮流,不弄虛作假肪凛!不忘初心堰汉!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市伟墙,隨后出現(xiàn)的幾起案子翘鸭,更是在濱河造成了極大的恐慌,老刑警劉巖戳葵,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件就乓,死亡現(xiàn)場離奇詭異,居然都是意外死亡拱烁,警方通過查閱死者的電腦和手機生蚁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來戏自,“玉大人邦投,你說我怎么就攤上這事∩帽剩” “怎么了志衣?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長猛们。 經(jīng)常有香客問我念脯,道長,這世上最難降的妖魔是什么弯淘? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任绿店,我火速辦了婚禮,結(jié)果婚禮上耳胎,老公的妹妹穿的比我還像新娘惯吕。我一直安慰自己惕它,他們只是感情好怕午,可當我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著淹魄,像睡著了一般郁惜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天兆蕉,我揣著相機與錄音羽戒,去河邊找鬼。 笑死虎韵,一個胖子當著我的面吹牛易稠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播包蓝,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼驶社,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了测萎?” 一聲冷哼從身側(cè)響起亡电,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎硅瞧,沒想到半個月后份乒,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡腕唧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年或辖,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枣接。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡孝凌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出月腋,到底是詐尸還是另有隱情蟀架,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布榆骚,位于F島的核電站片拍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏妓肢。R本人自食惡果不足惜捌省,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望碉钠。 院中可真熱鬧纲缓,春花似錦、人聲如沸喊废。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽污筷。三九已至工闺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背陆蟆。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工雷厂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人叠殷。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓改鲫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親林束。 傳聞我的和親對象是個殘疾皇子钩杰,可洞房花燭夜當晚...
    茶點故事閱讀 45,507評論 2 359

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