Search code examples
objective-cios4linked-listcontactsaddressbook

Getting merged/unified entries from ABAddressBook


I'm developing an application that is showing the iPhone contacts.

The ABAddressBookRef returns duplicate entries for a contact that appears only once in the iPhone contacts application.

Looking on the contact card (from the iPhone contacts), in the bottom there is a section called "Linked Contacts" so obviously apple "merge"/"unify" these two entries into the one i see.

The question here is what is the best way to mimic the same behavior so my app will show only one entry? is there an API that returns the merged/unified entries from the address book?


Solution

  • To create a list of contacts that merges in linked contacts:

    Note: ABPerson references are stored in custom Person class instances. All persons are then stored in a dictionary addressBookDictionary using recordID of each person as the key.


    1. Get all ABPersons using ABAddressBookCopyArrayOfAllPeople. Store persons in allPersonRecords array.

    2. Iterate through all ABPersons.


    2.1 Get a list of linked persons for each ABPerson. Use

    ABPersonCopyArrayOfAllLinkedPeople(ABRecordRef person);

    If there are no linked contacts, this method will return an array including the person reference him/herself. So if the return array has a count > 1, the person has linked contacts.

    2.2 Add the linked persons to a NSMutableSet. These linked persons will be skipped and not processed in future iterations.

    2.3 Create a Person instance for the current ABPerson.

    2.4 Merge linked person information into Person instance. A linked person may have different phone numbers, so you need to merge them together.


    NSArray *allPersonRecords = (NSArray *) ABAddressBookCopyArrayOfAllPeople(self.addressBook);
    NSMutableSet *linkedPersonsToSkip = [[NSMutableSet alloc] init];
    
    for (int i=0; i<[allPersonRecords count]; i++){
    
        ABRecordRef personRecordRef = [allPersonRecords objectAtIndex:i];
    
        // skip if contact has already been merged
        //
        if ([linkedPersonsToSkip containsObject:personRecordRef]) {
            continue;
        }
    
        // Create object representing this person
        //
        Person *thisPerson = [[Person alloc] initWithPersonRef:personRecordRef];
    
        // check if there are linked contacts & merge their contact information
        //
        NSArray *linked = (NSArray *) ABPersonCopyArrayOfAllLinkedPeople(personRecordRef);
        if ([linked count] > 1) {
            [linkedPersonsToSkip addObjectsFromArray:linked];
    
            // merge linked contact info
            for (int m = 0; m < [linked count]; m++) {
                ABRecordRef iLinkedPerson = [linked objectAtIndex:m];
                // don't merge the same contact
                if (iLinkedPerson == personRecordRef) {
                    continue;
                }
                [thisPerson mergeInfoFromPersonRef:iLinkedPerson];
            }
        }
        [self.addressBookDictionary setObject:thisPerson forKey:thisPerson.recordID];
        [thisPerson release];
        [linked release];
    }
    [linkedPersonsToSkip release];
    [allPersonRecords release];