Как выбрать контакт с ABPeoplePickerNavigationController в Swift?
Я добавил 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)
}
Спасибо!
3 ответа:
Пара мыслей:
Очевидно, что при использовании iOS 9 и более поздних версий вам следует отказаться от всего этого и использовать фреймворк
Установили ли вы свойство
peoplePickerDelegate
контроллера выбораpeople
? Если вы этого не сделаете, он не будет знать, чтобы попытаться вызвать эти методы в вашем классе. Таким образом:people.peoplePickerDelegate = self presentViewController(people, animated: true, completion: nil)
Ваш пример метода ссылается на
people
при вызовеABRecordCopyValue
. Это ваш контроллер выбора. Я предполагаю, что вы хотели сослаться наperson
,ABRecordRef!
, который был передан в качестве параметра.Вы также можете убедиться, что у вас действительно есть адрес электронной почты. прежде чем пытаться получить к нему доступ. Вы можете использовать
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 }
- Однако вместо того, чтобы предполагать, что пользователю нужен только первый адрес электронной почты, вы можете позволить ему щелкнуть и выбрать один из возможных нескольких адресов электронной почты, которые были у контакта. Итак, во-первых, возможно, вы захотите устранить некоторые из "шум", сообщая сборщику, что вы хотите видеть только адреса электронной почты:
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") }
Это дает пользователю визуальную индикацию есть ли даже адрес электронной почты для человека, и предотвращает их от выбора записи без адреса электронной почты.
ContactsUI
, что еще больше упрощает код.
Вот последний фреймворк для iOS 9-ContactsUI
Импорт ContactsUI
Соответствует CNContactPickerDelegate (нет обязательных методов)
Создайте объект выбора контактов и представьте его:
let peoplePicker = CNContactPickerViewController() peoplePicker.delegate = self self.presentViewController(peoplePicker, animated: true, completion: nil)
Отклонить CNContactPickerViewController в функции делегата contactPickerDidCancel
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 IOS10 Рабочая версия Jon 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) } } } } }