Reputation: 1075
I'm using ABAddressBook, I can display every contact, but I've some duplicate contact.
I've read this topic : Dealing with duplicate contacts due to linked cards in iOS' Address Book API, but can't fix the problem.
I would like to use this code in mine, but I don't succeed to.. :
NSMutableSet *unifiedRecordsSet = [NSMutableSet set];
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef records = ABAddressBookCopyArrayOfAllPeople(addressBook);
for (CFIndex i = 0; i < CFArrayGetCount(records); i++)
{
NSMutableSet *contactSet = [NSMutableSet set];
ABRecordRef record = CFArrayGetValueAtIndex(records, i);
[contactSet addObject:(__bridge id)record];
NSArray *linkedRecordsArray = (__bridge NSArray *)ABPersonCopyArrayOfAllLinkedPeople(record);
[contactSet addObjectsFromArray:linkedRecordsArray];
// Your own custom "unified record" class (or just an NSSet!)
DAUnifiedRecord *unifiedRecord = [[DAUnifiedRecord alloc] initWithRecords:contactSet];
[unifiedRecordsSet addObject:unifiedRecord];
CFRelease(record);
}
CFRelease(records);
CFRelease(addressBook);
_unifiedRecords = [unifiedRecordsSet allObjects];
Here is my code :
- (void)getPersonOutOfAddressBook
{
//1
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
if (addressBook != nil) {
NSLog(@"Succesful.");
//2
NSArray *allContacts = (__bridge_transfer NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
//3
NSUInteger i = 0; for (i = 0; i < [allContacts count]; i++)
{
Person *person = [[Person alloc] init];
ABRecordRef contactPerson = (__bridge ABRecordRef)allContacts[i];
//4
NSString *firstName = (__bridge_transfer NSString *)ABRecordCopyValue(contactPerson,
kABPersonFirstNameProperty);
if (firstName == nil)
{
firstName = @"";
}
NSString *lastName = (__bridge_transfer NSString *)ABRecordCopyValue(contactPerson, kABPersonLastNameProperty);
if (lastName == nil)
{
lastName = @"";
}
NSString *fullName = [NSString stringWithFormat:@"%@ %@", firstName, lastName];
person.firstName = firstName; person.lastName = lastName;
person.fullName = fullName;
//phone
//5
ABMultiValueRef phones = ABRecordCopyValue(contactPerson, kABPersonPhoneProperty);
//6
NSUInteger j = 0;
for (j = 0; j < ABMultiValueGetCount(phones); j++) {
NSString *phone = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(phones, j);
if (j == 0) {
person.mainNumber = phone;
}
else if (j==1) person.secondNumber = phone;
}
//7
[person.mainNumber stringByReplacingOccurrencesOfString:@" " withString:@""];
[person.mainNumber stringByReplacingOccurrencesOfString:@"(" withString:@""];
[person.mainNumber stringByReplacingOccurrencesOfString:@")" withString:@""];
[person.mainNumber stringByReplacingOccurrencesOfString:@"+336" withString:@"06"];
[self.tableData addObject:person];
[self.contact addObject:person.fullName];
}
//8
CFRelease(addressBook);
} else {
//9
NSLog(@"Error reading Address Book");
}
NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:@"fullName" ascending:YES];
[self.tableData sortUsingDescriptors:[NSArray arrayWithObject:sorter]];
}
Upvotes: 1
Views: 524
Reputation: 438277
If you want to avoid adding duplicates, it's probably easiest to build a set of the ABRecordID
values that have already had something added, and only add a contact if it doesn't exist in that set already:
self.tableData = [NSMutableArray array];
NSMutableSet *foundIDs = [NSMutableSet set];
NSArray *allContacts = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook));
for (id record in allContacts) {
ABRecordRef contactPerson = (__bridge ABRecordRef)record;
ABRecordID recordId = ABRecordGetRecordID(contactPerson);
if (![foundIDs containsObject:@(recordId)]) {
Person *person = [[Person alloc] init];
// get name
person.firstName = CFBridgingRelease(ABRecordCopyValue(contactPerson, kABPersonFirstNameProperty)) ?: @"";
person.lastName = CFBridgingRelease(ABRecordCopyValue(contactPerson, kABPersonLastNameProperty)) ?: @"";
person.fullName = [NSString stringWithFormat:@"%@ %@", person.firstName, person.lastName];
// get phones
ABMultiValueRef phones = ABRecordCopyValue(contactPerson, kABPersonPhoneProperty);
for (NSUInteger j = 0; j < ABMultiValueGetCount(phones); j++) {
// I presume you meant to use mutable string and `replaceOccurrencesOfString`:
NSMutableString *phone = [CFBridgingRelease(ABMultiValueCopyValueAtIndex(phones, j)) mutableCopy];
[phone replaceOccurrencesOfString:@" " withString:@"" options:0 range:NSMakeRange(0, phone.length)];
[phone replaceOccurrencesOfString:@"(" withString:@"" options:0 range:NSMakeRange(0, phone.length)];
[phone replaceOccurrencesOfString:@")" withString:@"" options:0 range:NSMakeRange(0, phone.length)];
[phone replaceOccurrencesOfString:@"+336" withString:@"06" options:0 range:NSMakeRange(0, phone.length)];
if (j == 0) person.mainNumber = phone;
else if (j==1) person.secondNumber = phone;
}
CFRelease(phones);
// add the `Person` record
[self.tableData addObject:person];
// add the ID for this person (and all linked contacts) to our set of `foundIDs`
NSArray *linkedPeople = CFBridgingRelease(ABPersonCopyArrayOfAllLinkedPeople(contactPerson));
if (linkedPeople) {
for (id record in linkedPeople) {
[foundIDs addObject:@(ABRecordGetRecordID((__bridge ABRecordRef)record))];
}
} else {
[foundIDs addObject:@(recordId)];
}
}
}
CFRelease(addressBook);
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"fullName" ascending:YES];
[self.tableData sortUsingDescriptors:@[descriptor]];
Having said that, you probably should iterate through all of the linked contacts and look for phone numbers there, too. Maybe do some validation of the names, too (e.g. if you have one entry for J. D. Salinger and another for John David Salinger, have some algorithm for figuring out which name you want to use). There's a lot you could do. But the above illustrates a minimalistic solution which adds the contact and any linked contacts to the list of contacts already found.
Upvotes: 3