parse literal declarar characters swift addressbook abaddressbook peoplepicker addressbookui

literal - ¿Cómo seleccionar un contacto con ABPeoplePickerNavigationController en Swift?



swift unicode character literal (3)

Aquí está el último marco para iOS 9 - ContactsUI

  1. importar ContactsUI

  2. Conforme con CNContactPickerDelegate (No se requieren métodos)

  3. Crea un objeto selector de contactos y preséntalo:

    let peoplePicker = CNContactPickerViewController() peoplePicker.delegate = self self.presentViewController(peoplePicker, animated: true, completion: nil)

  4. Descarte el CNContactPickerViewController en la función de delegado contactPickerDidCancel

    func contactPickerDidCancel(picker: CNContactPickerViewController) { picker.dismissViewControllerAnimated(true, completion: nil) }

  5. Aquí es cómo accedí al nombre de un contacto, números de teléfono, etiquetas de números de teléfono y foto usando la función de delegado 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") } } }

He añadido el ABPeoplePickerNavigationController en mi primer controlador de vista. Quiero que cuando seleccione un contacto muestre la información para mostrar en otro controlador de vista, pero estoy intentando usar mi código y esto no se muestra nunca cuando hago clic en un contacto. Esto solo abre el contacto en la aplicación nativa 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 }

Probé esta función

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

¡Gracias!


Un par de pensamientos:

  1. ¿Ha establecido la propiedad peoplePickerDelegate del controlador del selector de people ? Si no lo hace, no sabrá intentar llamar a estos métodos en su clase. Así:

    people.peoplePickerDelegate = self presentViewController(people, animated: true, completion: nil)

  2. Su método de ejemplo es hacer referencia a people cuando llama a ABRecordCopyValue . Ese es el controlador de su selector. Supongo que ABRecordRef! hacer referencia a la person , ABRecordRef! Eso fue pasado como un parámetro.

    También es posible que desee asegurarse de que realmente tiene una dirección de correo electrónico antes de intentar acceder a ella. Puede utilizar ABMultiValueGetCount .

    También creo que también puedes eliminar eso de la danza de fromOpaque / toOpaque .

    Esto produce:

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

  3. Si también necesitas soportar iOS 7, usa:

    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 }

  4. Sin embargo, en lugar de suponer que el usuario solo deseaba la primera dirección de correo electrónico, permítale que haga clic y elija una de las múltiples direcciones de correo electrónico posibles que tenía el contacto. Entonces, en primer lugar, es posible que desee eliminar parte del "ruido", indicando al selector que solo desea ver las direcciones de correo electrónico:

    people.peoplePickerDelegate = self people.displayedProperties = [NSNumber(int: kABPersonEmailProperty)] presentViewController(people, animated: true, completion: nil)

    Y luego, elimine el método anterior que hemos estado discutiendo y, en su lugar, implemente:

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

    Y para soportar iOS 7.0, también, agregarías:

    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 }

  5. Por cierto, iOS 8 ofrece una función para controlar si un contacto está habilitado o no. Ya que está soportando iOS 7 y 8, querría emplear eso condicionalmente, como por ejemplo:

    if people.respondsToSelector(Selector("predicateForEnablingPerson")) { people.predicateForEnablingPerson = NSPredicate(format: "emailAddresses.@count > 0") }

    Esto le da al usuario una indicación visual de si hay incluso una dirección de correo electrónico para el individuo, y le impide seleccionar una entrada sin dirección de correo electrónico.

Obviamente, si usa iOS 9 y versiones posteriores, debe retirar todo esto y usar el marco de ContactsUI , lo que simplifica aún más el código.


SWIFT3 IOS10 Versión de trabajo de para Swift 3 y IOS 10 y soporte para la selección de múltiples contactos.

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