8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

iOS8.0以降でABAddressBookUIの実装でハマったのでメモ

Last updated at Posted at 2015-05-11

 アドレス帳からメールアドレスを引っ張ってきたかったので、ABAddressBookとABAddressBookUIをimportして、デリゲートを設定したのにうまくいかず、かなりハマったのでメモ。

iOS7.x.xまでは、下記のデリゲートメソッドが呼ばれていましたが、

ViewController.swift
// Personを選択したとき呼ばれる(iOS8.0以前)
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!, shouldContinueAfterSelectingPerson person: ABRecord!) -> Bool {
    let multi: ABMultiValueRef = ABRecordCopyValue(person, kABPersonEmailProperty).takeRetainedValue()
    // メールアドレスが2件以上ある場合、
    if ABMultiValueGetCount(multi) > 1 {
        peoplePicker.displayedProperties = [NSNumber(int: kABPersonEmailProperty)]
        println("Selected Person has multiple mail addresses.")
        return true
    } else if ABMultiValueGetCount(multi) == 1 {
        // メールアドレスが1件だけの場合、
        let email = ABMultiValueCopyValueAtIndex(multi, 0).takeRetainedValue() as! String
            
        _userDefaults.setValue(email, forKey: "MailAddress")
        _userDefaults.synchronize()
        println("(iOS7)Selected Email address is: \(email)")

        _controller.popViewControllerAnimated(false)
        self.dismissViewControllerAnimated(true, completion: nil)
            
        return false
    } else {
        return false
    }
}

// ABPeoplePickerNavigationControllerで1つのプロパティ(電話番号やメールアドレス等)を選択したとき、
// デフォルトの処理(電話をかける、新規メール作成画面に遷移する等)を行うかどうかを返す。trueを返すとデフォルトの動作。
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!, shouldContinueAfterSelectingPerson person: ABRecord!, property: ABPropertyID, identifier: ABMultiValueIdentifier) -> Bool {
    let multi: ABMultiValueRef = ABRecordCopyValue(person, kABPersonEmailProperty).takeRetainedValue()
    let index: CFIndex = ABMultiValueGetIndexForIdentifier(multi, identifier)
        
    let email = ABMultiValueCopyValueAtIndex(multi, index).takeRetainedValue() as! String
        
    _userDefaults.setValue(email, forKey: "MailAddress")
    _userDefaults.synchronize()
    println("(iOS7.x)Selected Email address is: \(email)")
        
    _controller.popViewControllerAnimated(false)
    self.dismissViewControllerAnimated(true, completion: nil)
        
    return false
}

 iOS8.0以降では同メソッドはdeprecatedとなっていて、その代わりに下記のデリゲートメソッドが呼ばれることになっています。

ViewController.swift
// 選択したとき呼ばれる(iOS8.0以上のとき)
// ABPeoplePickerNavigationControllerで1つの連絡先を選択したとき、
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!, didSelectPerson person: ABRecord!) {
    let multi: ABMultiValueRef = ABRecordCopyValue(person, kABPersonEmailProperty).takeRetainedValue()
    // メールアドレスが2件以上ある場合、
    if ABMultiValueGetCount(multi) > 1 {
        peoplePicker.displayedProperties = [NSNumber(int: kABPersonEmailProperty)]
        println("Selected Person has multiple mail addresses.")
        return
    } else if ABMultiValueGetCount(multi) == 1 {
        // メールアドレスが1件だけの場合、
        let email = ABMultiValueCopyValueAtIndex(multi, 0).takeRetainedValue() as! String
            
        _userDefaults.setValue(email, forKey: "MailAddress")
        _userDefaults.synchronize()
        println("(iOS8)Selected Email address is: \(email)")
            
        _controller.popViewControllerAnimated(false)
        self.dismissViewControllerAnimated(true, completion: nil)
            
        return
    }
}

// 詳細画面から戻るときに呼ばれる(iOS8.0以降で呼ばれる)
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!, didSelectPerson person: ABRecord!, property: ABPropertyID, identifier: ABMultiValueIdentifier) {
    let multi: ABMultiValueRef = ABRecordCopyValue(person, kABPersonEmailProperty).takeRetainedValue()
    let index: CFIndex = ABMultiValueGetIndexForIdentifier(multi, identifier)
        
    let email = ABMultiValueCopyValueAtIndex(multi, index).takeRetainedValue() as! String
        
    _userDefaults.setValue(email, forKey: "MailAddress")
    _userDefaults.synchronize()
    println("(iOS8.x)Selected Email address is: \(email)")

    _controller.popToRootViewControllerAnimated(false)
    self.dismissViewControllerAnimated(true, completion: nil)
}

 しかし、デリゲートの設定して、上記のメソッドを実装してもなぜか呼ばれませんでした。

 いろいろ検索して調べた結果、下記が参考になりました。
Github:mattneub/Programming-iOS-Book-Examples

ViewController.swift
let _controller = ABPeoplePickerNavigationController()
// iOS8.0以上の対応
if _controller.respondsToSelector(Selector("predicateForEnablingPerson")) {
    // メールアドレスがない人は表示しない
    _controller.predicateForEnablingPerson = NSPredicate(format: "emailAddresses.@count > 0")
    // true:選択した人をアプリに返す、false:選択した人の詳細を表示する(iOS8.0以上対応)
    _controller.predicateForSelectionOfPerson = NSPredicate(value: false)
    // true:選択したプロパティをアプリに返す、false:選択した人の詳細データでデフォルトアクションを実行する(iOS8.0以上対応)
    _controller.predicateForSelectionOfProperty = NSPredicate(value: true)
}

上記のように、
_controller.predicate~
で条件を設定しないとデリゲートメソッドが呼ばれません。

Referenceをちゃんと読めば分かるんでしょうけど、ハマりました。

8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?