最初のビューコントローラにABPeoplePickerNavigationController
を追加しました。連絡先を選択したときに他のビューコントローラーに表示する情報を表示したいのですが、コードを使用しようとしていますが、連絡先をクリックしても表示されません。これにより、連絡先がネイティブアプリABPeoplePickerNavigationController
にのみ開かれます。
var people = ABPeoplePickerNavigationController()
var addressBook: ABAddressBookRef?
func extractABAddressBookRef(abRef: Unmanaged<ABAddressBookRef>!) -> ABAddressBookRef? {
if let ab = abRef {
self.view.addSubview(people.view)
return Unmanaged<NSObject>.fromOpaque(ab.toOpaque()).takeUnretainedValue()
}
return nil
}
この機能を試しました
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!,didSelectPerson person: ABRecordRef!) {
var unmanagedEmails = ABRecordCopyValue(people, kABPersonEmailProperty)
let emailObj: ABMultiValueRef = Unmanaged.fromOpaque(unmanagedEmails.toOpaque()).takeUnretainedValue() as NSObject as ABMultiValueRef
var index = 0 as CFIndex
var unmanagedEmail = ABMultiValueCopyValueAtIndex(emailObj, index)
var emailAddress:String = Unmanaged.fromOpaque(unmanagedEmail.toOpaque()).takeUnretainedValue() as NSObject as String
println(emailAddress)
}
ありがとう!
いくつかの考え:
peoplePickerDelegate
ピッカーコントローラーのpeople
プロパティを設定しましたか?そうしないと、クラスでこれらのメソッドを呼び出そうとしてもわかりません。したがって:
people.peoplePickerDelegate = self
presentViewController(people, animated: true, completion: nil)
メソッドの例では、people
を呼び出すときにABRecordCopyValue
を参照しています。それがピッカーコントローラーです。パラメータとして渡されたABRecordRef!
、person
を参照するつもりだったと思います。
また、メールアドレスにアクセスする前に、実際にメールアドレスがあることを確認することもできます。 ABMultiValueGetCount
を使用できます。
fromOpaque
/toOpaque
ダンスも排除できると思います。
これにより、
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController, didSelectPerson person: ABRecord) {
let emails: ABMultiValueRef = ABRecordCopyValue(person, kABPersonEmailProperty).takeRetainedValue()
if ABMultiValueGetCount(emails) > 0 {
let index = 0 as CFIndex
let emailAddress = ABMultiValueCopyValueAtIndex(emails, index).takeRetainedValue() as! String
print(emailAddress)
} else {
print("No email address")
}
}
IOS 7もサポートする必要がある場合は、次を使用します。
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController, shouldContinueAfterSelectingPerson person: ABRecord, property: ABPropertyID, identifier: ABMultiValueIdentifier) -> Bool {
let multiValue: ABMultiValueRef = ABRecordCopyValue(person, property).takeRetainedValue()
let index = ABMultiValueGetIndexForIdentifier(multiValue, identifier)
let email = ABMultiValueCopyValueAtIndex(multiValue, index).takeRetainedValue() as! String
print("email = \(email)")
peoplePicker.dismissViewControllerAnimated(true, completion: nil)
return false
}
ただし、ユーザーが最初のメールアドレスしか必要としない場合は、代わりに、クリックして連絡先が持つ可能性のある複数のメールアドレスの1つを選択するようにしてください。したがって、最初に、ピッカーにメールアドレスのみを表示したいことを伝えることにより、「ノイズ」の一部を排除することができます。
people.peoplePickerDelegate = self
people.displayedProperties = [NSNumber(int: kABPersonEmailProperty)]
presentViewController(people, animated: true, completion: nil)
次に、これまで説明してきた以前のメソッドを削除し、代わりに実装します。
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!, didSelectPerson person: ABRecordRef!, property: ABPropertyID, identifier: ABMultiValueIdentifier) {
let multiValue: ABMultiValueRef = ABRecordCopyValue(person, property).takeRetainedValue()
let index = ABMultiValueGetIndexForIdentifier(multiValue, identifier)
let email = ABMultiValueCopyValueAtIndex(multiValue, index).takeRetainedValue() as String
println("email = \(email)")
}
また、iOS 7,0もサポートするために、次のように追加します。
func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController, shouldContinueAfterSelectingPerson person: ABRecord, property: ABPropertyID, identifier: ABMultiValueIdentifier) -> Bool {
let multiValue: ABMultiValueRef = ABRecordCopyValue(person, property).takeRetainedValue()
let index = ABMultiValueGetIndexForIdentifier(multiValue, identifier)
let email = ABMultiValueCopyValueAtIndex(multiValue, index).takeRetainedValue() as! String
print("email = \(email)")
peoplePicker.dismissViewControllerAnimated(true, completion: nil)
return false
}
ちなみに、iOS 8には、連絡先を有効にするかどうかを制御する機能があります。 iOS 7および8をサポートしているので、次のように条件付きで使用する必要があります。
if people.respondsToSelector(Selector("predicateForEnablingPerson")) {
people.predicateForEnablingPerson = NSPredicate(format: "emailAddresses.@count > 0")
}
これにより、ユーザーにメールアドレスが存在するかどうかをユーザーに視覚的に示し、メールアドレスのないエントリを選択できないようにします。
明らかに、iOS 9以降を使用している場合は、これらすべてを廃止し、ContactsUI
フレームワークを使用する必要があります。これにより、コードがさらに簡素化されます。
こちらがiOS 9の最新フレームワークです-ContactsUI
contactsUIをインポートする
CNContactPickerDelegate に準拠(必要なメソッドはありません)
連絡先ピッカーオブジェクトを作成して表示します。
let peoplePicker = CNContactPickerViewController()
peoplePicker.delegate = self
self.presentViewController(peoplePicker, animated: true, completion: nil)
ContactPickerDidCancelデリゲート関数のCNContactPickerViewControllerを閉じます
func contactPickerDidCancel(picker: CNContactPickerViewController) {
picker.dismissViewControllerAnimated(true, completion: nil)
}
次に、didSelectContactデリゲート関数を使用して連絡先の名前、電話番号、電話番号ラベル、写真にアクセスする方法を示します。
func contactPicker(picker: CNContactPickerViewController, didSelectContact contact: CNContact) {
//Dismiss the picker VC
picker.dismissViewControllerAnimated(true, completion: nil)
//See if the contact has multiple phone numbers
if contact.phoneNumbers.count > 1 {
//If so we need the user to select which phone number we want them to use
let multiplePhoneNumbersAlert = UIAlertController(title: "Which one?", message: "This contact has multiple phone numbers, which one did you want use?", preferredStyle: UIAlertControllerStyle.Alert)
//Loop through all the phone numbers that we got back
for number in contact.phoneNumbers {
//Each object in the phone numbers array has a value property that is a CNPhoneNumber object, Make sure we can get that
if let actualNumber = number.value as? CNPhoneNumber {
//Get the label for the phone number
var phoneNumberLabel = number.label
//Strip off all the extra crap that comes through in that label
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("_", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("$", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("!", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("<", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString(">", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
//Create a title for the action for the UIAlertVC that we display to the user to pick phone numbers
let actionTitle = phoneNumberLabel + " - " + actualNumber.stringValue
//Create the alert action
let numberAction = UIAlertAction(title: actionTitle, style: UIAlertActionStyle.Default, handler: { (theAction) -> Void in
//Create an empty string for the contacts name
var nameToSave = ""
//See if we can get A frist name
if contact.givenName == "" {
//If Not check for a last name
if contact.familyName == "" {
//If no last name set name to Unknown Name
nameToSave = "Unknown Name"
}else{
nameToSave = contact.familyName
}
}else{
nameToSave = contact.givenName
}
// See if we can get image data
if let imageData = contact.imageData {
//If so create the image
let userImage = UIImage(data: imageData)
}
//Do what you need to do with your new contact information here!
//Get the string value of the phone number like this:
actualNumber.stringValue
})
//Add the action to the AlertController
multiplePhoneNumbersAlert.addAction(numberAction)
}
}
//Add a cancel action
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: { (theAction) -> Void in
//Cancel action completion
})
//Add the cancel action
multiplePhoneNumbersAlert.addAction(cancelAction)
//Present the ALert controller
self.presentViewController(multiplePhoneNumbersAlert, animated: true, completion: nil)
}else{
//Make sure we have at least one phone number
if contact.phoneNumbers.count > 0 {
//If so get the CNPhoneNumber object from the first item in the array of phone numbers
if let actualNumber = contact.phoneNumbers.first?.value as? CNPhoneNumber {
//Get the label of the phone number
var phoneNumberLabel = contact.phoneNumbers.first!.label
//Strip out the stuff you don't need
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("_", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("$", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("!", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("<", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString(">", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
//Create an empty string for the contacts name
var nameToSave = ""
//See if we can get A frist name
if contact.givenName == "" {
//If Not check for a last name
if contact.familyName == "" {
//If no last name set name to Unknown Name
nameToSave = "Unknown Name"
}else{
nameToSave = contact.familyName
}
}else{
nameToSave = contact.givenName
}
// See if we can get image data
if let imageData = contact.imageData {
//If so create the image
let userImage = UIImage(data: imageData)
}
//Do what you need to do with your new contact information here!
//Get the string value of the phone number like this:
actualNumber.stringValue
}
}else{
//If there are no phone numbers associated with the contact I call a custom funciton I wrote that lets me display an alert Controller to the user
self.displayAlert("Missing info", message: "You have no phone numbers associated with this contact")
}
}
}
Swift3 IOS10Jon Vogel の作業バージョンSwift 3およびIOS 10および複数の連絡先の選択をサポートします。
//
// Created by JEFFERSON A NEITZKE on 30/01/17.
// Copyright © 2017 JEFFERSON A NEITZKE. All rights reserved.
//
import UIKit
import ContactsUI
class Principal: UIViewController, CNContactPickerDelegate {
var numeroADiscar: String = ""
var userImage: UIImage? = nil
var nameToSave = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let peoplePicker = CNContactPickerViewController()
peoplePicker.delegate = self
self.present(peoplePicker, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
picker.dismiss(animated: true, completion: nil)
}
func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
// I only want single selection
if contacts.count != 1 {
return
} else {
//Dismiss the picker VC
picker.dismiss(animated: true, completion: nil)
let contact: CNContact = contacts[0]
//See if the contact has multiple phone numbers
if contact.phoneNumbers.count > 1 {
//If so we need the user to select which phone number we want them to use
let multiplePhoneNumbersAlert = UIAlertController(title: "Which one?", message: "This contact has multiple phone numbers, which one did you want use?", preferredStyle: UIAlertControllerStyle.alert)
//Loop through all the phone numbers that we got back
for number in contact.phoneNumbers {
//Each object in the phone numbers array has a value property that is a CNPhoneNumber object, Make sure we can get that
let actualNumber = number.value as CNPhoneNumber
//Get the label for the phone number
var phoneNumberLabel = number.label
//Strip off all the extra crap that comes through in that label
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: "_", with: "")
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: "$", with: "")
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: "!", with: "")
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: "<", with: "")
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: ">", with: "")
//Create a title for the action for the UIAlertVC that we display to the user to pick phone numbers
let actionTitle = phoneNumberLabel! + " - " + actualNumber.stringValue
//Create the alert action
let numberAction = UIAlertAction(title: actionTitle, style: UIAlertActionStyle.default, handler: { (theAction) -> Void in
//See if we can get A frist name
if contact.givenName == "" {
//If Not check for a last name
if contact.familyName == "" {
//If no last name set name to Unknown Name
self.nameToSave = "Unknown Name"
}else{
self.nameToSave = contact.familyName
}
} else {
self.nameToSave = contact.givenName
}
// See if we can get image data
if let imageData = contact.imageData {
//If so create the image
self.userImage = UIImage(data: imageData)!
}
//Do what you need to do with your new contact information here!
//Get the string value of the phone number like this:
self.numeroADiscar = actualNumber.stringValue
})
//Add the action to the AlertController
multiplePhoneNumbersAlert.addAction(numberAction)
}
//Add a cancel action
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: { (theAction) -> Void in
//Cancel action completion
})
//Add the cancel action
multiplePhoneNumbersAlert.addAction(cancelAction)
//Present the ALert controller
self.present(multiplePhoneNumbersAlert, animated: true, completion: nil)
} else {
//Make sure we have at least one phone number
if contact.phoneNumbers.count > 0 {
//If so get the CNPhoneNumber object from the first item in the array of phone numbers
let actualNumber = (contact.phoneNumbers.first?.value)! as CNPhoneNumber
//Get the label of the phone number
var phoneNumberLabel = contact.phoneNumbers.first!.label
//Strip out the stuff you don't need
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: "_", with: "")
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: "$", with: "")
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: "!", with: "")
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: "<", with: "")
phoneNumberLabel = phoneNumberLabel?.replacingOccurrences(of: ">", with: "")
//Create an empty string for the contacts name
self.nameToSave = ""
//See if we can get A frist name
if contact.givenName == "" {
//If Not check for a last name
if contact.familyName == "" {
//If no last name set name to Unknown Name
self.nameToSave = "Unknown Name"
}else{
self.nameToSave = contact.familyName
}
} else {
nameToSave = contact.givenName
}
// See if we can get image data
if let imageData = contact.imageData {
//If so create the image
self.userImage = UIImage(data: imageData)
}
//Do what you need to do with your new contact information here!
//Get the string value of the phone number like this:
self.numeroADiscar = actualNumber.stringValue
} else {
//If there are no phone numbers associated with the contact I call a custom funciton I wrote that lets me display an alert Controller to the user
let alert = UIAlertController(title: "Missing info", message: "You have no phone numbers associated with this contact", preferredStyle: UIAlertControllerStyle.alert)
let cancelAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alert.addAction(cancelAction)
present(alert, animated: true, completion: nil)
}
}
}
}
}