Получение объединенных / унифицированных записей из ABAddressBook

Я разрабатываю приложение, которое показывает контакты iPhone.

ABAddressBookRef возвращает повторяющиеся записи для контакта, который появляется только один раз в приложении контактов iPhone.

Глядя на карточку контакта (из контактов iPhone), внизу есть раздел под названием «Связанные контакты», поэтому очевидно, что яблоко «объединяет» / «объединяет» эти две записи в ту, которую я вижу.

Вопрос в том, как лучше всего имитировать одно и то же поведение, чтобы мое приложение отображало только одну запись? есть ли API, который возвращает объединенные / объединенные записи из адресной книги?


person Amir Naor    schedule 01.11.2010    source источник


Ответы (2)


Чтобы создать список контактов, который объединяется в связанные контакты:

Примечание. Ссылки ABPerson хранятся в экземплярах настраиваемого класса Person. Затем все люди сохраняются в словаре addressBookDictionary, используя recordID каждого человека в качестве ключа.


1. Получите всех ABPersons с помощью ABAddressBookCopyArrayOfAllPeople. Сохраните людей в массиве allPersonRecords.

2. Перебрать все ABPersons.


2.1. Получите список связанных лиц для каждого ABPerson. Используйте

ABPersonCopyArrayOfAllLinkedPeople (человек ABRecordRef);

Если связанных контактов нет, этот метод вернет массив, включающий человека, который ссылается на себя. Итак, если в возвращаемом массиве счетчик> 1, у человека есть связанные контакты.

2.2 Добавьте связанных лиц в NSMutableSet. Эти связанные лица будут пропущены и не будут обрабатываться в будущих итерациях.

2.3 Создайте экземпляр Person для текущего ABPerson.

2.4 Объедините информацию о связанном человеке с экземпляром Person. Связанное лицо может иметь разные номера телефонов, поэтому вам необходимо объединить их вместе.


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];
person Min Tsai    schedule 08.04.2012
comment
привет, не могли бы вы описать, какой класс Person содержится в вашем коде? - person HarshIT; 21.01.2013
comment
Опишите, пожалуйста - Класс человека не найден .. @MinTsai - person Ashish Kakkad; 24.02.2014
comment
Класс Person - это просто его собственный класс для хранения контактной информации для каждого человека, он в основном соответствует моему собственному формату (кроме именования). initWithPersonRef вызовет AbRecordCopyValue для personRecordRef для полей, которые он хочет сохранить, и сохранит их в переменных / свойствах экземпляра, созданных в объекте Person. Не копируйте / не вставляйте код, не понимая его, вы создадите себе гораздо более серьезные проблемы в долгосрочной перспективе, когда вам действительно придется поддерживать код. И спасибо Харрису за решение этой проблемы. - person SafeFastExpressive; 17.08.2014
comment
Как вы думаете, может ли быть лучший способ добиться этого, если у нас будет огромное количество контактов ... скажем, 5000? Спасибо. - person sole007; 11.12.2014
comment
Где метод? mergeInfoFromPersonRef? Или мы должны написать это сами? - person Sam B; 20.02.2015
comment
@ sole007 У меня такая же проблема, когда подобные решения плохо масштабируются. Как только вы пройдете отметку в 2k контакта, это станет дорого. Пока Apple не предоставит собственный способ сделать это, я в растерянности. - person JRam13; 31.08.2015

Вам нужно взглянуть на функцию с именем:

CFArrayRef ABPersonCopyArrayOfAllLinkedPeople (человек ABRecordRef);

Эта функция определена в ABPerson.h. Вы передаете ABRecordRef для человека, и функция возвращает массив объектов ABRecordRef, представляющих карточки адресной книги, которые связаны с человеком, которого вы передали.

  1. Сделайте изменяемую копию массива, содержащего записи адресной книги, которые были возвращены из ABAddressBookRef. Для обсуждения назовите этот новый массив finalContacts.

  2. Перебрать исходный массив контактов.

  3. Для каждой записи в массиве вызовите указанную выше функцию и передайте текущую запись. Вы получите список связанных объектов ABPersonRef. Удалите все эти записи из массива finalContacts.

  4. После итерации все связанные карточки должны быть удалены из "finalContacts", и вы должны остаться с уникальным списком карточек адресной книги.

person Carter    schedule 23.09.2011
comment
звучит достаточно справедливо ... но, может быть, нам стоит взглянуть на то, для чего нужны связанные контакты? - person hfossli; 05.10.2011
comment
также удаление ссылок «мама», «помощник» и других из списка для отображения в списке звучит странно .. (?) - person hfossli; 05.10.2011
comment
@hfossli: ABPersonCopyArrayOfAllLinkedPeople(person) возвращает массив других записей для того же человека. Ссылки на Супруга, Помощника и т. Д. Возвращаются ABRecordCopyValue(person, kABPersonRelatedNamesProperty). - person David Hull; 13.12.2012