Unable to access kABPersonNoteProperty

I have the following code which copies data from the iPhone’s contacts into an NSMutableDictionary. I’m using optional binding as discussed in this answer.

The firstName and lastName fields copy properly (as well as phone and email fields not shown here), but I have never been able to access the kABPersonNoteProperty, nor have I seen the println statement in the log. I’ve tried to copy the note as both String and NSString without success. Any ideas what could be causing this problem?

  • Check if device supports blur
  • Set “OTHER_LDFLAGS” through command line with xcodebuild
  • Firebase or Swift not detecting umlauts
  • iOS custom shape navigation bar
  • UICollectionView Scrolling is Very Choppy
  • Delaying function in swift
  • var contactInfoDict:NSMutableDictionary!
    
    func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!, didSelectPerson person: ABRecord!) {
    
        self.contactInfoDict = ["firstName":"", "lastName":"", "notes":""]
    
        if let firstName:String = ABRecordCopyValue(person, kABPersonFirstNameProperty)?.takeRetainedValue() as? String {
            contactInfoDict.setObject(firstName, forKey: "firstName")
            println(firstName)
        }
    
        if let lastName:String = ABRecordCopyValue(person, kABPersonLastNameProperty)?.takeRetainedValue() as? String {
            contactInfoDict.setObject(lastName, forKey: "lastName")
            println(lastName)
        }
    
        if let notes:String = ABRecordCopyValue(person, kABPersonNoteProperty)?.takeRetainedValue() as? String {
            contactInfoDict.setObject(notes, forKey: "notes")
            println("Note: \(notes)")
        }
    
    }
    

    Edit Here is the full class:

    import UIKit
    import AddressBookUI
    
    class ContactsVC: UIViewController, ABPeoplePickerNavigationControllerDelegate {
    
    @IBOutlet weak var done_Btn: UIBarButtonItem!
    @IBAction func dismissContacts(sender: UIBarButtonItem) {
        self.dismissViewControllerAnimated(true, completion: nil)
        println("ContactsVC dismissed")
    }
    
    @IBOutlet weak var viewContainer: UIView!
    
    var object:PFObject = PFObject(className: "Contact")
    let personPicker: ABPeoplePickerNavigationController
    var contactInfoDict:NSMutableDictionary!
    
    required init(coder aDecoder: NSCoder) {
        personPicker = ABPeoplePickerNavigationController()
        super.init(coder: aDecoder)
        personPicker.peoplePickerDelegate = self
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        done_Btn.setTitleTextAttributes([NSFontAttributeName: UIFont(name: "Avenir Next Medium", size: 16)!], forState: UIControlState.Normal)
    
    }
    
    
    @IBAction func addContact() {
    
        let actionSheetController: UIAlertController = UIAlertController(title: nil, message: "Would you like to select a contact from your iPhone or create a new contact directly in the app?", preferredStyle: .ActionSheet)
    
        let selectContactAction: UIAlertAction = UIAlertAction(title: "Select from iPhone", style: .Default) { action -> Void in
            self.performPickPerson(UIAlertAction)
        }
        actionSheetController.addAction(selectContactAction)
    
        let createContactAction: UIAlertAction = UIAlertAction(title: "Create App Contact", style: .Default) { action -> Void in
            self.performSegueWithIdentifier("AddContact", sender: self)
        }
        actionSheetController.addAction(createContactAction)
    
        let cancelAction:UIAlertAction = UIAlertAction(title: "Cancel", style: .Cancel) {
            action -> Void in
        }
        actionSheetController.addAction(cancelAction)
    
        self.presentViewController(actionSheetController, animated: true, completion: nil)
    }
    
    
    func performPickPerson(sender : AnyObject) {
        self.presentViewController(personPicker, animated: true, completion: nil)
    }
    
    
    func peoplePickerNavigationControllerDidCancel(peoplePicker: ABPeoplePickerNavigationController!) {
        personPicker.dismissViewControllerAnimated(true, completion: nil)
    }
    
    func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!, didSelectPerson person: ABRecord!) {
    
        self.contactInfoDict = ["firstName":"", "lastName":"", "company":"", "mobilePhone":"", "homePhone":"", "workPhone":"", "personalEmail":"", "workEmail":"", "street":"", "city":"", "state":"", "zipCode":"", "notes":""]
    
        if let firstName:String = ABRecordCopyValue(person, kABPersonFirstNameProperty)?.takeRetainedValue() as? String {
            contactInfoDict.setObject(firstName, forKey: "firstName")
            println(firstName)
        }
    
        if let lastName:String = ABRecordCopyValue(person, kABPersonLastNameProperty)?.takeRetainedValue() as? String {
            contactInfoDict.setObject(lastName, forKey: "lastName")
            println(lastName)
        }
    
        if let company:String = ABRecordCopyValue(person, kABPersonOrganizationProperty)?.takeRetainedValue() as? String {
            contactInfoDict.setObject(company, forKey: "company")
            println(company)
        }
    
    
        if let phonesRef:ABMultiValueRef = ABRecordCopyValue(person, kABPersonPhoneProperty)?.takeRetainedValue() as ABMultiValueRef? {
            for (var i = 0; i < ABMultiValueGetCount(phonesRef); i++ ) {
                var currentPhoneLabel:CFStringRef = ABMultiValueCopyLabelAtIndex(phonesRef, i).takeRetainedValue()
                var currentPhoneValue:CFStringRef = ABMultiValueCopyValueAtIndex(phonesRef, i)?.takeRetainedValue() as! CFStringRef
    
                if let mobileResult = CFStringCompare(currentPhoneLabel, kABPersonPhoneMobileLabel, CFStringCompareFlags.CompareCaseInsensitive) as CFComparisonResult? {
                    if mobileResult == CFComparisonResult.CompareEqualTo {
                        contactInfoDict.setObject(currentPhoneValue, forKey: "mobilePhone")
                    }
                }
    
                if let homeResult = CFStringCompare(currentPhoneLabel, kABHomeLabel, CFStringCompareFlags.CompareCaseInsensitive) as CFComparisonResult? {
                    if homeResult == CFComparisonResult.CompareEqualTo {
                        contactInfoDict.setObject(currentPhoneValue, forKey: "homePhone")
                    }
                }
                if let workResult = CFStringCompare(currentPhoneLabel, kABWorkLabel, CFStringCompareFlags.CompareCaseInsensitive) as CFComparisonResult? {
                    if workResult == CFComparisonResult.CompareEqualTo {
                        contactInfoDict.setObject(currentPhoneValue, forKey: "workPhone")
                    }
                }
            }
    
        }
    
        if let emailsRef:ABMultiValueRef = ABRecordCopyValue(person, kABPersonEmailProperty)?.takeRetainedValue() as ABMultiValueRef? {
            for (var i = 0; i < ABMultiValueGetCount(emailsRef); i++ ) {
                var currentEmailLabel:CFStringRef = ABMultiValueCopyLabelAtIndex(emailsRef, i).takeRetainedValue()
                var currentEmailValue:CFStringRef = ABMultiValueCopyValueAtIndex(emailsRef, i)?.takeRetainedValue() as! CFStringRef
    
                if let email = kABHomeLabel as CFStringRef? {
                    if let homeResult = CFStringCompare(currentEmailLabel, kABHomeLabel, CFStringCompareFlags.CompareCaseInsensitive) as CFComparisonResult? {
                        if homeResult == CFComparisonResult.CompareEqualTo {
                            contactInfoDict.setObject(currentEmailValue as String, forKey: "personalEmail")
                        }
                    }
                }
                if let workResult = CFStringCompare(currentEmailLabel, kABWorkLabel, CFStringCompareFlags.CompareCaseInsensitive) as CFComparisonResult? {
                    if workResult == CFComparisonResult.CompareEqualTo {
                        contactInfoDict.setObject(currentEmailValue as String, forKey: "workEmail")
                    }
                }
            }
        }
    
        if let addressRef:ABMultiValueRef = ABRecordCopyValue(person, kABPersonAddressProperty)?.takeRetainedValue() as ABMultiValueRef? {
            if ABMultiValueGetCount(addressRef) > 0 {
                var addressDict:NSDictionary = ABMultiValueCopyValueAtIndex(addressRef, 0)?.takeRetainedValue() as! NSDictionary
    
                if let street = addressDict.objectForKey(kABPersonAddressStreetKey) as? String {
                    contactInfoDict.setObject(street as NSString, forKey: "street")
                }
    
                if let city = addressDict.objectForKey(kABPersonAddressCityKey) as? String {
                    contactInfoDict.setObject(city as NSString, forKey: "city")
                }
    
                if let state = addressDict.objectForKey(kABPersonAddressStateKey) as? String {
                    contactInfoDict.setObject(state as NSString, forKey: "state")
                }
    
                if let zipCode = addressDict.objectForKey(kABPersonAddressZIPKey) as? String {
                    contactInfoDict.setObject(zipCode as NSString, forKey: "zipCode")
                }
            }
        }
    
        // Notes is not currently accessible
        if let note:String = ABRecordCopyValue(person, kABPersonNoteProperty)?.takeRetainedValue() as? String {
            println("12")
            contactInfoDict.setObject(note, forKey: "notes")
            println("Note: \(note)")
        }
    
        saveToContact()
    }
    
    func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!, shouldContinueAfterSelectingPerson person: ABRecord!, property: ABPropertyID, identifier: ABMultiValueIdentifier) -> Bool {
        return false
    }
    
    
    func saveToContact(){
        self.object["username"] = PFUser.currentUser()!
    
        if let firstName = contactInfoDict["firstName"] as? String{
            self.object["contactFirstName"] = firstName
        }
    
        if let lastName = contactInfoDict["lastName"] as? String{
            self.object["contactLastName"] = lastName
        }
    
        if let company = contactInfoDict["company"] as? String{
            self.object["contactCompany"] = company
        }
    
        if let mobilePhone = contactInfoDict["mobilePhone"] as? String{
            self.object["contactMobilePhone"] = mobilePhone
        }
    
        if let homePhone = contactInfoDict["homePhone"] as? String{
            self.object["contactHomePhone"] = homePhone
        }
    
        if let workPhone = contactInfoDict["workPhone"] as? String{
            self.object["contactWorkPhone"] = workPhone
        }
    
        if let personalEmail = contactInfoDict["personalEmail"] as? String{
            self.object["contactPersonalEmail"] = personalEmail
        }
    
        if let workEmail = contactInfoDict["workEmail"] as? String{
            self.object["contactWorkEmail"] = workEmail
        }
    
        if let street = contactInfoDict["street"] as? String{
            self.object["contactStreet"] = street
        }
    
        if let city = contactInfoDict["city"] as? String{
            self.object["contactCity"] = city
        }
    
        if let state = contactInfoDict["state"] as? String{
            self.object["contactState"] = state
        }
    
        if let zipCode = contactInfoDict["zipCode"] as? String{
            self.object["contactZipCode"] = zipCode
        }
    
        if let notes = contactInfoDict["notes"] as? String{
            self.object["contactNotes"] = notes
        }
    
        self.object["contactType"] = "Lead"
    
        self.object["contactIsActive"] = true
    
    
        var addrObject = self.object
        self.object.pinInBackgroundWithName("Contacts")
        self.object.saveEventually{ (success, error) -> Void in
            if (error == nil) {
                println("saved in background")
            } else {
                println(error!.userInfo)
            }
        }
    }
    
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    }
    

    Solutions Collect From Internet About “Unable to access kABPersonNoteProperty”

    I just tested it and it works fine, just as you have it. This is effectively my whole code (except for getting authorization, of course):

    @IBAction func doPeoplePicker (sender:AnyObject!) {
        let picker = ABPeoplePickerNavigationController()
        picker.peoplePickerDelegate = self
        self.presentViewController(picker, animated:true, completion:nil)
    }
    
    func peoplePickerNavigationController(peoplePicker: ABPeoplePickerNavigationController!, 
    didSelectPerson person: ABRecord!) {
        if let note = ABRecordCopyValue(person, kABPersonNoteProperty)?.takeRetainedValue() as? String {
            println(note)
        } else {
            println("no note")
        }
    }
    

    When my person has a note, I see it; when my person has no note, I see “no note”.

    EDIT You and I played around with this for a while, sending each other actual projects, and I observed the following difference between your implementation and mine: mine, for which fetching the note works, obtains authorization to access the address book (you’ll notice that I did mention that, in the first paragraph of my original answer); yours, for which fetching the note doesn’t work, doesn’t obtain authorization. Hence, I suggest that this is the missing piece of the puzzle.

    Here’s my theory. Prior to iOS 8, you needed authorization in order to use ABPeoplePickerNavigationController. Thus, my code, which goes way back, still obtains it. The way this supposedly works in iOS 8 is that, in the absence of authorization, the people picker fetches a copy of the address book data. Well, I think that this copy is faulty (and that you should file a bug report with Apple about this). But because I have authorization, I’m accessing the actual address book data, and so my code can see the note.