I am retrieving contact's multiple addresses but only want Home address - ios

Does anyone know how to retrieve the Home address from multiaddress in iOS? I have got permission from user and everything else but the problem is, I only want the Home address.
ABAddressBookRef addressBook = ABAddressBookCreate();
__block BOOL accessGranted = NO;
if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
accessGranted = granted;
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
dispatch_release(sema);
}
else { // we're on iOS 5 or older
accessGranted = YES;
}
if (accessGranted) {
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
NSMutableArray *array = [[NSMutableArray alloc] init];
for( int i = 0 ; i < nPeople ; i++ )
{
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i );
// First Name
NSString *fName = (__bridge NSString*)ABRecordCopyValue(ref, kABPersonFirstNameProperty);
// Last Name
NSString *lName = (__bridge NSString*)ABRecordCopyValue(ref, kABPersonLastNameProperty);
// Phone
ABMultiValueRef phoneMultiValue = ABRecordCopyValue(ref, kABPersonPhoneProperty);
CFArrayRef allPhones = ABMultiValueCopyArrayOfAllValues(phoneMultiValue);
NSMutableArray *phoneData = [NSMutableArray arrayWithArray:(__bridge NSArray*) allPhones];
// Email
ABMultiValueRef emailMultiValue = ABRecordCopyValue(ref, kABPersonEmailProperty);
CFArrayRef allEmails = ABMultiValueCopyArrayOfAllValues(emailMultiValue);
NSMutableArray *emailData = [NSMutableArray arrayWithArray:(__bridge NSArray*) allEmails];
// Address
ABMultiValueRef addressMultiValue = ABRecordCopyValue(ref, kABPersonAddressProperty);
CFArrayRef allAddresses = ABMultiValueCopyArrayOfAllValues(addressMultiValue);
NSMutableArray* addressData = [NSMutableArray arrayWithArray:(__bridge NSArray*) allAddresses];
for ( int j = 0 ; j < [addressData count]; j++) {
if ([[addressData objectAtIndex:j] count] > 0) {
if ([fName length] > 0 || [lName length] > 0) {
if ([fName length] > 0) {
[dic setObject:fName forKey:#"FirstName"];
}
if ([lName length] > 0) {
[dic setObject:lName forKey:#"LastName"];
}
if ([phoneData count] > 0) {
[dic setObject:phoneData forKey:#"MultiplePhoneNumbers"];
}
if ([emailData count] > 0) {
[dic setObject:emailData forKey:#"MultipleEmails"];
}
[dic setObject:addressData forKey:#"MultipleAddresses"];
}
}
}
NSUInteger keyCount = [[dic allKeys] count];
if (keyCount > 0) {
ABRecordID recId = ABRecordGetRecordID(ref);
[dic setObject:[NSString stringWithFormat:#"%d",recId] forKey:#"ABRecordRef"];
[dic setObject:[NSString stringWithFormat:#"%d",i] forKey:#"ab_id"];
[dic setObject:[NSNumber numberWithBool:FALSE] forKey:#"is_coordinate_fetch"];
[array addObject:dic];
}
I would really appreciate if anyone could take time and solve this for me.

You need to iterate through the kABPersonAddressProperty multivalue property and extract the one matching the kABHomeLabel identifier. Here is how you could do it in iOS 7 (assumes a reference to the address book):
NSArray *people = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(localAddressBook));
// Iterate through each person in the Address Book
for (NSUInteger i = 0; i < people.count; i++)
{
ABRecordRef person = CFArrayGetValueAtIndex((__bridge CFArrayRef)people, i);
// Access the person's addresses (a ABMultiValueRef)
ABMultiValueRef addressesProperty = CFAutorelease(ABRecordCopyValue(person, kABPersonAddressProperty));
if (addressesProperty)
{
// Iterate through the address multivalue
for (CFIndex index = 0; index < ABMultiValueGetCount(addressesProperty); index++)
{
// Get the address label
NSString *addressLabel = (NSString *)CFBridgingRelease(ABMultiValueCopyLabelAtIndex(addressesProperty, index));
// Check for home address label
if ([addressLabel isEqualToString:(NSString *)kABHomeLabel])
{
// Your code here
NSLog(#"%#", addressLabel);
}
}
}
}

There is no single solution to this problem. What I did in my app to do this was as follows:
1) If the person just had one address, use that.
2) If there was more than one address, using cells that had the name and the first address, and a button that said "Select different Address". If the user taps that button, animate up a sheet where the user sees another table of all addresses, and can choose the one they want.

Related

how to save one name string and two different length array of email and phone no

As i guess this is a very simple and basic question.
i am using #import <AddressBook/AddressBook.h> to get the contact info of device and i had successfully implemented the same.
Everythings work fine when i got one phone no and one email from each contact. But when i got multiple phone no's and multiple email then getting crash on my app. I guess i am not using the proper saving method.
So i really want to know how to save one name string and one array of email(different length) and phone no(different length) as group for a contact and same for all other. so that it would not be difficult to reproduce the result later on the detail screen
CFErrorRef *error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex numberOfPeople = ABAddressBookGetPersonCount(addressBook);
for(int i = 0; i < numberOfPeople; i++) {
ABRecordRef person = CFArrayGetValueAtIndex( allPeople, i );
NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonLastNameProperty));
[values1 addObject:[NSString stringWithFormat:#"%# %#",firstName,lastName]]; //values1 array to save name of contact
ABMultiValueRef emails = ABRecordCopyValue(person, kABPersonEmailProperty);
for (CFIndex j=0; j < ABMultiValueGetCount(emails); j++) {
NSString* email = (__bridge NSString*)ABMultiValueCopyValueAtIndex(emails, j);
NSLog(#"Email:%#", email);
[values2 addObject:[NSString stringWithFormat:#"%#",email]];
} //values2 array to save email associated to that contact
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
for (CFIndex i = 0; i < ABMultiValueGetCount(phoneNumbers); i++) {
NSString *phoneNumber = (__bridge_transfer NSString *) ABMultiValueCopyValueAtIndex(phoneNumbers, i);
NSLog(#"phone:%#", phoneNumber);
[values3 addObject:[NSString stringWithFormat:#"%#",phoneNumber]];
}//values3 array to save different phone no's associated to that contacts
NSDictionary *dict = [[NSDictionary alloc]init];
}
AS now i have three array with details contain details of one contact. Now how can merge these three array values to one so that it would be easy to save and fetch data for multiples or hundreds of contacts
ABAddressBookRef allPeople = ABAddressBookCreate();
CFArrayRef allContacts = ABAddressBookCopyArrayOfAllPeople(allPeople);
CFIndex numberOfContacts = ABAddressBookGetPersonCount(allPeople);
NSLog(#"numberOfContacts------------------------------------%ld",numberOfContacts);
for(int i = 0; i < numberOfContacts; i++){
NSString* name = #"";
NSString* phone = #"";
NSString* email = #"";
ABRecordRef aPerson = CFArrayGetValueAtIndex(allContacts, i);
ABMultiValueRef fnameProperty = ABRecordCopyValue(aPerson, kABPersonFirstNameProperty);
ABMultiValueRef lnameProperty = ABRecordCopyValue(aPerson, kABPersonLastNameProperty);
ABMultiValueRef phoneProperty = ABRecordCopyValue(aPerson, kABPersonPhoneProperty);\
ABMultiValueRef emailProperty = ABRecordCopyValue(aPerson, kABPersonEmailProperty);
NSArray *emailArray = (__bridge NSArray *)ABMultiValueCopyArrayOfAllValues(emailProperty);
NSArray *phoneArray = (__bridge NSArray *)ABMultiValueCopyArrayOfAllValues(phoneProperty);
if (fnameProperty != nil) {
name = [NSString stringWithFormat:#"%#", fnameProperty];
}
if (lnameProperty != nil) {
name = [name stringByAppendingString:[NSString stringWithFormat:#" %#", lnameProperty]];
}
if ([phoneArray count] > 0) {
if ([phoneArray count] > 1) {
for (int i = 0; i < [phoneArray count]; i++) {
phone = [phone stringByAppendingString:[NSString stringWithFormat:#"%#\n", [phoneArray objectAtIndex:i]]];
}
}else {
phone = [NSString stringWithFormat:#"%#", [phoneArray objectAtIndex:0]];
}
}
if ([emailArray count] > 0) {
if ([emailArray count] > 1) {
for (int i = 0; i < [emailArray count]; i++) {
email = [email stringByAppendingString:[NSString stringWithFormat:#"%#\n", [emailArray objectAtIndex:i]]];
}
}else {
email = [NSString stringWithFormat:#"%#", [emailArray objectAtIndex:0]];
}
}
NSLog(#"NAME : %#",name);
NSLog(#"PHONE: %#",phone);
NSLog(#"EMAIL: %#",email);
NSLog(#"\n");
}
You can see multiple contact and email in log if contact have.

Is it possible to check a contact whether it is exits in contact list of iPhone or not?

I am developing an app in which i have to save contact in address book, but if the the contact is already saved in contact then it should not save.
But i have no idea is it possible to check a contact whether it is exits in contact list of iPhone or not?
Any help would be appreciated.
Thanks in advance.
Solved issue
-(void)CheckContactIsExits{
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
NSArray *allContacts = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
ABRecordRef pet = ABPersonCreate();
ABRecordSetValue(pet, kABPersonFirstNameProperty, (__bridge CFStringRef)#"VoxSci Activation", nil);
for (id record in allContacts){
ABRecordRef thisContact = (__bridge ABRecordRef)record;
if (CFStringCompare(ABRecordCopyCompositeName(thisContact),
ABRecordCopyCompositeName(pet), 0) == kCFCompareEqualTo){
NSLog(#"The contact already exists");
//The contact already exists!
isContactExits=YES;
}
}
}
Assuming your using Apples framework for this your user will be given the option to "create new contact" or if its already in the contacts list "add to existing contact". Therefore the user can decide if it should be added or not
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>
And read all the contacts in iPhone and check the name or phone exit or not.
Check Contact is Exit or Not By Contact Number
Note : Only replace checkingPhoneNumber variable by your checking contact number
ABAddressBookRef * addressbook = ABAddressBookCreateWithOptions(Nil, Nil);
NSArray *people = (__bridge NSArray*)ABAddressBookCopyArrayOfAllPeople(addressbook);
NSMutableArray *phoneArray=[[NSMutableArray alloc] init];
for(id person in people)
{
// get person contact number
ABMultiValueRef phones = (ABMultiValueRef)ABRecordCopyValue((__bridge ABRecordRef)(person), kABPersonPhoneProperty);
NSString* mobile=#"";
NSString* mobileLabel;
for (int i=0; i < ABMultiValueGetCount(phones); i++)
{
mobileLabel = (__bridge NSString*)ABMultiValueCopyLabelAtIndex(phones, i);
if([mobileLabel isEqualToString:(NSString *)kABPersonPhoneMobileLabel]) {
NSLog(#"mobile:");
} else if ([mobileLabel isEqualToString:(NSString*)kABPersonPhoneIPhoneLabel]) {
NSLog(#"iphone:");
} else if ([mobileLabel isEqualToString:(NSString*)kABPersonPhonePagerLabel]) {
NSLog(#"pager:");
}
mobile = (__bridge NSString*)ABMultiValueCopyValueAtIndex(phones, i);
NSLog(#"%#", mobile);
// remove all spaces bracket from contact number
NSMutableString *newPhoneStr = [[NSMutableString alloc] init];;
int j = [mobile length];
for (int i=0; i<j; i++)
{
if ([mobile characterAtIndex:i] >=48 && [mobile characterAtIndex:i] <=59)
{
[newPhoneStr appendFormat:#"%c",[mobile characterAtIndex:i]];
}
}
//add contact into phoneArray
[phoneArray addObject:newPhoneStr];
}
}
NSLog(#"%#",phoneArray);
BOOL identicalStringFound = NO;
// remove all spaces bracket from contact number which is check
NSMutableString *newCheckingPhoneNumberStr = [[NSMutableString alloc] init];
int j = [checkingPhoneNumber length];
for (int i=0; i<j; i++)
{
if ([checkingPhoneNumber characterAtIndex:i] >=48 && [[profileDetailsDict valueForKey:#"mobile"] characterAtIndex:i] <=59)
{
[newCheckingPhoneNumberStr appendFormat:#"%c",[checkingPhoneNumber characterAtIndex:i]];
}
}
for (NSString *contact in phoneArray)
{
if ([contact isEqual:newCheckingPhoneNumberStr])
{
identicalStringFound = YES;
break;
}
}
if(identicalStringFound)
{
// checkingPhoneNumber is exit
}
else
{
// checkingPhoneNumber is not exit
}
If anybody wants to check name is saved in address book or not, then below function may be useful:
-(BOOL)isNameSaved:(NSString*)strGivenName {
BOOL isSaved = NO;
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
for ( int i = 0; i < nPeople; i++ ) {
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i);
CFStringRef firstc = (CFStringRef)ABRecordCopyValue(ref, kABPersonFirstNameProperty);
NSString *first = [NSString stringWithFormat:#"%#",firstc];
if ([first isEqualToString:strGivenName]) {
isSaved = YES;
break;
}
}
return isSaved;
}

Application crashes while fetching the iPhone's contact list in iOS

I am having the trouble to fetch iPhone contacts.
I have tried to fetch the contact by the following code.
It is working fine in simulator and also worked fine when the contacts are less in the contact list.
In my phone I am having 1000 Contacts. So it crashes on this device. Please guide me if you know the reason.
Here is my code.
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
ABRecordRef source = ABAddressBookCopyDefaultSource(addressBook);
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, source, kABPersonSortByFirstName);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
NSMutableArray* items = [NSMutableArray arrayWithCapacity:nPeople];
for (int i = 0; i < nPeople; i++)
{
NSMutableDictionary *dicContacts = [[NSMutableDictionary alloc]init];
ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
NSMutableArray *phoneNumbers = [[NSMutableArray alloc] init];
ABMultiValueRef multiPhones = ABRecordCopyValue(person, kABPersonPhoneProperty);
for(CFIndex i=0;i<ABMultiValueGetCount(multiPhones);i++)
{
CFStringRef phoneNumberRef = ABMultiValueCopyValueAtIndex(multiPhones, i);
NSString *phoneNumber = (__bridge NSString *) phoneNumberRef;
[phoneNumbers addObject:phoneNumber];
//NSLog(#"All numbers %#", phoneNumbers);
}
if ([phoneNumbers count] > 0) {
[dicContacts setValue:[phoneNumbers objectAtIndex:0] forKeyPath:#"Contact"];
}
[items addObject:dicContacts];
}
Thanks In Advance
-(void)tkPeoplePickerController:(TKPeoplePickerController*)picker didFinishPickingDataWithInfo:(NSArray*)contacts
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CFErrorRef *error = nil;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL,error);
[contacts enumerateObjectsUsingBlock:^(id obj,NSUInteger idx, BOOL *stop)
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
TKContact *contact = (TKContact*)obj;
NSNumber *personID = [NSNumber numberWithInt:contact.recordID];
ABRecordID abRecordID = (ABRecordID)[personID intValue];
ABRecordRef abPerson = ABAddressBookGetPersonWithRecordID(addressBook, abRecordID);
// Check person image
UIImage *personImage = nil;
if (abPerson != nil && ABPersonHasImageData(abPerson))
{
if ( &ABPersonCopyImageDataWithFormat != nil )
{
// iOS >= 4.1
CFDataRef contactThumbnailData = ABPersonCopyImageDataWithFormat(abPerson, kABPersonImageFormatThumbnail);
personImage = [UIImage imageWithData:(__bridge NSData*)contactThumbnailData];
CFRelease(contactThumbnailData);
ABMultiValueRef emailValues = ABRecordCopyValue(abPerson, kABPersonEmailProperty);
// This is how you extract the first item from the multivalues:
CFStringRef cfEmailAddress = ABMultiValueCopyValueAtIndex(emailValues, 0);
// This is how you convert it to an NSString.
[RSVP_ImageArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
contact.name,#"name",
contact.email,#"email",
[NSString stringWithFormat:#"%d",abRecordID],#"recodeID",
savedImagePath,#"Image",
nil]];
CFDataRef contactImageData = ABPersonCopyImageDataWithFormat(abPerson, kABPersonImageFormatOriginalSize);
CFRelease(contactImageData);
}
else
{
// iOS < 4.1
CFDataRef contactImageData = ABPersonCopyImageData(abPerson);
personImage = [[UIImage imageWithData:(__bridge NSData*)contactImageData] thumbnailImage:CGSizeMake(thumbnailSize, thumbnailSize)];
ABMultiValueRef emailValues = ABRecordCopyValue(abPerson, kABPersonEmailProperty);
// This is how you extract the first item from the multivalues:
CFStringRef cfEmailAddress = ABMultiValueCopyValueAtIndex(emailValues, 0);
// This is how you convert it to an NSString.
[RSVP_ImageArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
contact.name,#"name",
contact.email,#"email",
[NSString stringWithFormat:#"%d",abRecordID],#"recodeID",
savedImagePath,#"Image",
nil]];
CFRelease(contactImageData);
}
}
else
{
ABMultiValueRef emailValues = ABRecordCopyValue(abPerson, kABPersonEmailProperty);
// This is how you extract the first item from the multivalues:
CFStringRef cfEmailAddress = ABMultiValueCopyValueAtIndex(emailValues, 0);
// This is how you convert it to an NSString.
[mutablearray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
contact.name,#"name",
contact.email,#"email",
[NSString stringWithFormat:#"%d",abRecordID],#"recodeID",
savedImagePath,#"Image",
nil]];
}
}
dispatch_async(dispatch_get_main_queue(), ^{
});
[pool drain];
}];
dispatch_async(dispatch_get_main_queue(), ^{
CFRelease(addressBook);
});
});
}
Use this code with it will surely help you.. for reference u can use this link https://github.com/qnibus/TKContactsMultiPicker ... :)
for(CFIndex i=0;i<ABMultiValueGetCount(multiPhones);i++)
{
CFStringRef phoneNumberRef = ABMultiValueCopyValueAtIndex(multiPhones, i);
NSString *phoneNumber = (__bridge NSString *) phoneNumberRef;
[phoneNumbers addObject:[NSString stringWithFormat:#"%#",phoneNumber]];
//NSLog(#"All numbers %#", phoneNumbers);
}
[phoneNumbers retain];

iOS open specific contact info

i know how to call the contact view but if someone could tell me how to call a specific contact .
To call the view i am calling this method
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
[self presentModalViewController:picker animated:YES];
and i am getting the info and storing in into plist
+ (NSInteger) exportContacts
{
ABAddressBookRef addressBook = ABAddressBookCreate();
__block BOOL accessGranted = NO;
if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
accessGranted = granted;
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
dispatch_release(sema);
}
else { // we're on iOS 5 or older
accessGranted = YES;
}
NSMutableArray *array = [[NSMutableArray alloc] init];
if (accessGranted) {
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
for( int i = 0 ; i < nPeople ; i++ )
{
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i );
// First Name
NSString *fName = (__bridge NSString*)ABRecordCopyValue(ref, kABPersonFirstNameProperty);
// Record Id
int recid = ABRecordGetRecordID(ref);
NSLog(#"Record Id %d",recid);
// Last Name
NSString *lName = (__bridge NSString*)ABRecordCopyValue(ref, kABPersonLastNameProperty);
// Phone
ABMultiValueRef phoneMultiValue = ABRecordCopyValue(ref, kABPersonPhoneProperty);
CFArrayRef allPhones = ABMultiValueCopyArrayOfAllValues(phoneMultiValue);
NSMutableArray *phoneData = [NSMutableArray arrayWithArray:(__bridge NSArray*) allPhones];
// Email
ABMultiValueRef emailMultiValue = ABRecordCopyValue(ref, kABPersonEmailProperty);
CFArrayRef allEmails = ABMultiValueCopyArrayOfAllValues(emailMultiValue);
NSMutableArray *emailData = [NSMutableArray arrayWithArray:(__bridge NSArray*) allEmails];
// Address
ABMultiValueRef addressMultiValue = ABRecordCopyValue(ref, kABPersonAddressProperty);
CFArrayRef allAddresses = ABMultiValueCopyArrayOfAllValues(addressMultiValue);
NSMutableArray* addressData = [NSMutableArray arrayWithArray:(__bridge NSArray*) allAddresses];
for ( int j = 0 ; j < [addressData count]; j++) {
if ([[addressData objectAtIndex:j] count] > 0) {
if ([fName length] > 0 || [lName length] > 0) {
if ([fName length] > 0) {
[dic setObject:fName forKey:#"FirstName"];
}
if ([lName length] > 0) {
[dic setObject:lName forKey:#"LastName"];
}
if ([phoneData count] > 0) {
[dic setObject:phoneData forKey:#"MultiplePhoneNumbers"];
}
if ([emailData count] > 0) {
[dic setObject:emailData forKey:#"MultipleEmails"];
}
[dic setObject:addressData forKey:#"MultipleAddresses"];
// store the ref id here
NSLog(#"%#",addressData);
}
}
}
NSUInteger keyCount = [[dic allKeys] count];
if (keyCount > 0) {
[dic setObject:[NSString stringWithFormat:#"%d",i] forKey:#"ab_id"];
[dic setObject:[NSNumber numberWithBool:FALSE] forKey:#"is_coordinate_fetch"];
[array addObject:dic];
}
}
[ApplicationUtility setPlistDataWithKey:KEY_ADDRESS_BOOK WithObject:array];
}
return [array count];
}
Take a look at the ABPersonViewController class reference.

ABAddressBookRef leaking in iOS

I'm parsing the address book in iOS but the Leaks instrument is reporting big memory leaks, I can't seem to track the problem down
First I create the address book.
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
This is what I suspect is leaking, but ABAddressBookRef and CFArrayRef get autoreleased right?
The rest of my code is below..
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
NSMutableArray *List = [[NSMutableArray alloc] init];
for (int i = 0; i < nPeople; i++) {
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i);
NSNumber *recordId = [NSNumber numberWithInteger:ABRecordGetRecordID(ref)];
CFStringRef firstName = ABRecordCopyValue(ref, kABPersonFirstNameProperty);
CFStringRef lastName = ABRecordCopyValue(ref, kABPersonLastNameProperty);
CFDataRef imgData = ABPersonCopyImageData(ref);
ABMutableMultiValueRef multi = ABMultiValueCreateMutable(kABMultiStringPropertyType);
multi = ABRecordCopyValue(ref,kABPersonEmailProperty);
for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++) {
CFStringRef email, emailLabel;
emailLabel = ABMultiValueCopyLabelAtIndex(multi, i);
email = ABMultiValueCopyValueAtIndex(multi, i);
NSString *emails = [NSString stringWithFormat: #"%#", (NSString *)email];
if (emails)
{
NSMutableDictionary *addDict = [[NSMutableDictionary alloc] init];
[addDict addObject:emails forKey:#"email"];
[List addObject:addDict];
[addDict release];
}
CFRelease(email);
CFRelease(emailLabel);
}
if (firstName) {
CFRelease(firstName);
}
if (lastName) {
CFRelease(lastName);
}
if (imgData) {
CFRelease(imgData);
}
if (ref) {
CFRelease(ref);
}
CFRelease(multi);
}
//do something with list
[List release];
Ok this works and doesn't leak
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
NSMutableArray *List = [[NSMutableArray alloc] init];
for (int x = 0; x < nPeople; x++) {
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, x);
ABMultiValueRef emailMultiValue = ABRecordCopyValue(ref, kABPersonEmailProperty);
NSArray *emailAddresses = [(NSArray *)ABMultiValueCopyArrayOfAllValues(emailMultiValue) autorelease];
for (int i = 0; i < [emailAddresses count]; i++) {
NSString *emails = [emailAddresses objectAtIndex:i];
if (emails)
{
NSMutableDictionary *addDict = [[NSMutableDictionary alloc] init];
[addDict addObject:emails forKey:#"email"];
[List addObject:addDict];
[addDict release];
}
}
if (emailMultiValue)
{
CFRelease(emailMultiValue);
}
if (ref) {
CFRelease(ref);
}
}
//do something with list
[List release];
CFRelease(allPeople);
Actually to eliminate all leaks you also need to be releasing the ABAddressBookRef - just follow Core Foundation naming guidelines - you got the reference using "ABAddressBookCreate()" and any function with Create or Copy needs to be released.
CFErrorRef error = NULL;
ABAddressBookRef addressbk=ABAddressBookCreateWithOptions(NULL, &error);
if (addressbk != nil)
{
NSLog(#"Succesful.");
NSArray *allContacts=(NSArray *)ABAddressBookCopyArrayOfAllPeople(addressbk); //type casting nsarray from CFArrayRef
NSUInteger i = 0;
for (i = 0; i < [allContacts count]; i++)
{
Category *mCategory = [[Category alloc]init];
ABRecordRef contactPerson = ( ABRecordRef)allContacts[i];
NSString *firstName = ( NSString *)ABRecordCopyValue(contactPerson, kABPersonFirstNameProperty);
NSString *lastName = ( NSString *)ABRecordCopyValue(contactPerson, kABPersonLastNameProperty);
NSString *fullName = [NSString stringWithFormat:#"%# %#", firstName, lastName];
mCategory.firstName = firstName;
mCategory.lastName = lastName;
mCategory.fullName = fullName;
//email
ABMultiValueRef emails = ABRecordCopyValue(contactPerson, kABPersonEmailProperty);
NSUInteger j = 0;
for (j = 0; j < ABMultiValueGetCount(emails); j++)
{
NSString *email = ( NSString *)ABMultiValueCopyValueAtIndex(emails, j);
if (j == 0)
{
mCategory.homeEmail = email;
NSLog(#"mCategory.homeEmail = %# ", mCategory.homeEmail);
}
else if (j==1)
mCategory.workEmail = email;
}
[self.arrAddress addObject:mCategory];
[mCategory release];
mCategory=nil;
}
}
CFRelease(addressbk);

Resources