objective-cmacosabaddressbookabperson

How to (easily) update an ABPerson object with a vCard and keep its unique ID?


The AddressBook Framework offers a great method for initializing an ABPerson with a vCard, by using the initWithVCardRepresentation: method.

What I want to do is update a contact with a certain vCard. I can't use initWithVCardRepresentation: because this will give me a new ABPerson object with a new uniqueId and I want to keep the uniqueId in between these changes.

What's an easy way to go about doing something like this?

Thanks!


Solution

  • initWithVCardRepresentation is still the slickest way to turn your vCard into an ABPerson.

    Just use the results of it to find the matching person in your Address Book and then iterate over the vCard properties, placing them into the existing record. The save at the end will harden your changes.

    The following example assumes that the unique "keys" will be last-name, first-name. You can modify the search element if you want to include companies where no name is listed or whatever, or you could change the iteration scheme by getting [AddressBook people], and then iterating over the people and using only those records where the key-value pairs match to your satisfaction.

    - (void)initOrUpdateVCardData:(NSData*)newVCardData {
        ABPerson* newVCard = [[ABPerson alloc] initWithVCardRepresentation:newVCardData];
        ABSearchEleemnt* lastNameSearchElement
          = [ABPerson searchElementForProperty:kABLastNameProperty
                                         label:nil
                                           key:nil
                                         value:[newVCard valueForProperty:kABLastNameProperty]
                                    comparison:kABEqualCaseInsensitive];
        ABSearchEleemnt* firstNameSearchElement
          = [ABPerson searchElementForProperty:kABFirstNameProperty
                                         label:nil
                                           key:nil
                                         value:[newVCard valueForProperty:kABFirstNameProperty]
                                    comparison:kABEqualCaseInsensitive];
        NSArray* searchElements
          = [NSArray arrayWithObjects:lastNameSearchElement, firstNameSearchElement, nil];
        ABSearchElement* searchCriteria
          = [ABSearchElement searchElementForConjunction:kABSearchAnd children:searchElements];
        AddressBook* myAddressBook = [AddressBook sharedAddressBook];
        NSArray* matchingPersons = [myAddressBook recordsMatchingSearchElement:searchCriteria];
        if (matchingPersons.count == 0)
        {
            [myAddressBook addRecord:newVCard];
        }
        else if (matchingPersons.count > 1)
        {
            // decide how to handle error yourself here: return, or resolve conflict, or whatever
        }
        else
        {
            ABRecord* existingPerson = matchingPersons.lastObject;
            for (NSString* property in [ABPerson properties])   // i.e. *all* potential properties
            {
                // if the property doesn't exist in the address book, value will be nil
                id value = [newVCard valueForProperty:property];
                if (value)
                {
                    NSError* error;
                    if (![existingPerson setValue:value forProperty:property error:&error] || error)
                        // handle error
                }
            }
            // newVCard with it's new unique-id will now be thrown away
        }
        [myAddressBook save];
    }