代码之家  ›  专栏  ›  技术社区  ›  user3745888

如何在Swift中选择ABPeoplePickerNavigationController联系人?

  •  19
  • user3745888  · 技术社区  · 10 年前

    我已添加 ABPeoplePickerNavigationController 进入我的第一个视图控制器。当我选择一个联系人时,我希望显示要在其他视图控制器中显示的信息,但我正在尝试使用我的代码,当我单击联系人时,这不会显示。这只会将联系人打开到本机应用程序 ABPeoplePicker导航控制器 .

    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 回复  |  直到 10 年前
        1
  •  18
  •   Jon Vogel    9 年前

    以下是iOS 9的最新框架-ContactsUI

    1. 导入联系人UI

    2. 符合 CNContactPickerDelegate (无需方法)

    3. 创建联系人选择器对象并将其显示:

      let peoplePicker = CNContactPickerViewController()
      
      peoplePicker.delegate = self
      
      self.presentViewController(peoplePicker, animated: true, completion: nil)
      
    4. 在contactPickerDidCancel委托函数中禁用CNContactPickerViewController

      func contactPickerDidCancel(picker: CNContactPickerViewController) {
          picker.dismissViewControllerAnimated(true, completion: nil)
      }
      
    5. 以下是我如何使用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")
          }
      }
      }
      
        2
  •  17
  •   Rob    9 年前

    有几个想法:

    1. 你把 peoplePickerDelegate 的属性 people 选择器控制器?如果不这样做,它就不知道如何在类中调用这些方法。因此:

      people.peoplePickerDelegate = self
      presentViewController(people, animated: true, completion: nil)
      
    2. 示例方法引用 当你打电话时 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")
          }
      }
      
    3. 如果您也需要支持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
      }
      
    4. 不过,你可以不假设用户只想要第一个电子邮件地址,而是让他们点击并从联系人可能拥有的多个电子邮件地址中选择一个。因此,首先,您可能希望通过告诉选择器您只想查看电子邮件地址来消除一些“噪音”:

      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(peoplePixer:ABPeoplePickerNavigationController,should ContinueAfterSelectingPerson person:ABRecord,property:ABPropertyID,identifier:ABMultiValueIdentifier)->布尔{
      let multiValue:ABMultiValueRef=ABRecordCopyValue(个人,财产).takeRetainedValue()
      let index=ABMultiValueGetIndexForIdentifier(多值,标识符)
      let email=ABMultiValueCopyValueAtIndex(multiValue,索引)。将RetainedValue()作为!一串
      
      打印(“电子邮件=\(电子邮件)”)
      
      peoplePicker.diseaseViewControllerAnimated(true,完成:nil)
      
      return false
      }
      
    5. 顺便说一句,iOS 8提供了一个功能来控制联系人是否已启用。由于您支持iOS 7和8,因此您希望有条件地使用它,例如:

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

      这为用户提供了一个直观的指示,即是否有个人的电子邮件地址,并防止他们选择没有电子邮件地址的条目。

    显然,如果使用iOS 9和更高版本,您应该取消所有这些功能,并使用 ContactsUI 框架,这进一步简化了代码。

        3
  •  9
  •   Community Lee Campbell    7 年前

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