app crashes when using kABPersinPhoneProperty - iphone

I am trying to get all the phone number from the Phone Book of iPhone. But my app crashes as soon as I try to fetch the number using kABPersonPhoneProperty. The code snippet is here
ABAddressBookRef addressBook = ABAddressBookCreate();
NSMutableArray *allPeople = (NSMutableArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);
int nPeople = ABAddressBookGetPersonCount(addressBook);
CFRelease(addressBook);
for(int i=0; i < nPeople; i++ ){
ABRecordRef person = [allPeople objectAtIndex:i];
NSString *name = #"";
CFTypeRef fName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
CFTypeRef lName = ABRecordCopyValue(person, kABPersonLastNameProperty);
ABMultiValueRef multi = ABRecordCopyValue(person , kABPersonPhoneProperty);
NSString *number = (NSString *)ABMultiValueCopyValueAtIndex(multi, 0);
if ([number length] > 0) {
if(fName != NULL)
{
if (lName != NULL) {
name = [[NSString stringWithFormat:#"%#", fName] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
else {
name = [[NSString stringWithFormat:#"%#", fName] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
NSLog(#"Number==>%# ",number);
}
}
if (fName != NULL) {
CFRelease(fName);
}
if (lName != NULL) {
CFRelease(lName);
}
if (multi != NULL) {
CFRelease(multi);
}
}
[allPeople release];
I am unable to figure out the error in this. I am also releasing everything even then it is not running smoothly.
I am even getting potential memory leak when running build and analyze for the code part
ABMultiValueRef multi = ABRecordCopyValue(person , kABPersonPhoneProperty);
NSLog(#"Number===>%d" , ABMultiValueGetCount(multi));
Please help me out to come.
Any kind of help would be highly appreciated.
Thanks in advance

Thanks for the response. I have figured out the solution fot the problem here. I did not release number variable thinking that the reference was passed as reference but it is copied to the returned location, hence need to release number after the usage.
thanks again for all the responses!!

Related

fetching only mobile section record (not from iphone, home label etc) from addressbook?

How do I fetch only mobile section record from addressbook in ios?
I want to add only one record to my array that is fetched from mobile section record.
How do I do that. I am getting all the phone property records. but I need to get only mobile section record.
NSArray *allPeople = (NSArray *)ABAddressBookCopyArrayOfAllPeople(myAddressBook);
NSLog(#"allpeople%#", allPeople);
for (id record in allPeople) {
CFTypeRef phoneProperty = ABRecordCopyValue((ABRecordRef)record, kABPersonPhoneProperty);
NSArray *phones = (NSArray *)ABMultiValueCopyArrayOfAllValues(phoneProperty);
NSLog(#"phones %#",phones);
CFRelease(phoneProperty);
NSMutableDictionary *newRecord = [[NSMutableDictionary alloc] init];
NSMutableString *newPhone = [[NSMutableString alloc] init];
for (NSString *phone in phones) {
if(![newPhone isEqualToString:#""])
[newPhone appendString:#", "];
[newPhone appendString:phone];
}
You can try something like this..
ABMultiValueRef phoneNumbers = ABRecordCopyValue(abPerson, kABPersonPhoneProperty);
if (phoneNumbers) {
CFIndex numberOfPhoneNumbers = ABMultiValueGetCount(phoneNumbers);
for (CFIndex i = 0; i < numberOfPhoneNumbers; i++) {
NSString *phone = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(phoneNumbers, i);
CFStringRef label = ABMultiValueCopyLabelAtIndex(phoneNumbers, i);
if (label) {
if (CFEqual(label, kABPersonPhoneMobileLabel)) {
primaryPhoneText.text = phone;
} else {
}
CFRelease(label);
[allPhones addObject:phone]; // allPhones is an array here.
}
}
CFRelease(phoneNumbers);
}
Hope this will help you out..
Enjoy coding..

Optimize Objective C code to access contacts

I have some code to copy contacts from Addreesbook. It works perfectly if there is a small number of contacts. Now In my phone there us 1200 contacts and the app crashes when I tried to copy them. Can anyone help me to optimize this code or rewrite code? The code I am using is added below:
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
NSString *requestContactsString = #"<contacts>";
for (int i=0; i<nPeople; i++)
{
NSLog(#"Started : %d", i);
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i);
CFTypeRef firstName = ABRecordCopyValue(ref, kABPersonFirstNameProperty);
CFTypeRef lastName = ABRecordCopyValue(ref, kABPersonLastNameProperty);
CFTypeRef email = ABRecordCopyValue(ref, kABPersonEmailProperty);
CFTypeRef phone = ABRecordCopyValue(ref, kABPersonPhoneProperty);
requestContactsString = [requestContactsString stringByAppendingFormat:#"<item>"];
if(firstName)
{
requestContactsString = [requestContactsString stringByAppendingFormat:#"<firstname>%#</firstname>", firstName];
CFRelease(firstName);
firstName = nil;
}
if(lastName)
{
requestContactsString = [requestContactsString stringByAppendingFormat:#"<lastname>%#</lastname>", lastName];
CFRelease(lastName);
lastName = nil;
}
if(email)
{
if(ABMultiValueGetCount(email)>0)
{
CFTypeRef em = ABMultiValueCopyValueAtIndex(email, 0);
requestContactsString = [requestContactsString stringByAppendingFormat:#"<email>%#</email>", em];
CFRelease(em);
}
CFRelease(email);
email = nil;
}
if(phone)
{
if(ABMultiValueGetCount(phone)>0)
{
CFTypeRef ph = ABMultiValueCopyValueAtIndex(phone, 0);
requestContactsString = [requestContactsString stringByAppendingFormat:#"<phone>%#</phone>", ph];
CFRelease(ph);
}
CFRelease(phone);
phone = nil;
}
requestContactsString = [requestContactsString stringByAppendingFormat:#"</item>"];
}
if(allPeople)
{
CFRelease(allPeople);
allPeople = nil;
}
if(addressBook)
{
CFRelease(addressBook);
addressBook = nil;
}
requestContactsString = [requestContactsString stringByAppendingFormat:#"</contacts>"];
NSString *hashedContactsString = [self generateHashedPassword:requestContactsString];
The major inefficiency I can see is the use of [NSString stringByAppendingFormat] which is creating a new NSString object each time it's called. This means that you have a large number of long auto-released NSString objects that are no longer being used until the next run loop (unless you are using ARC, in which case the situation is probably better).
I think you would make much better use of memory, and get better performance, by making requestContactsString an NSMutableString and using [NSMutableString appendString] (reference) instead. This would modify the existing object, allocating more memory to accept the new string.
Each append would look like this:
[requestContactsString appendString:[NSString stringWithFormat:#"<lastname>%#</lastname>", lastName]];
Which still creates a large number of auto-released objects, but they are much smaller.
Use a NSMutableString and build your XML with the appendFormat: method. In your loop you are copying the whole string you've assembled so far multiple times.

Fix Potential leak of an object

When i used build and analyse, i got leaks( it showed as potential leak of an object). to fix that i included as below
if ( aContactfirstName){
CFRelease(aContactfirstName);
}
if (aContactLastName){
CFRelease(aContactLastName);
}
But my app crashes.
So pls let me know where it leaks and solve it.
-(NSString*)getContactNameByPhoneNo:(NSString*)phoneNO{
NSString *aContactName = phoneNO;
ABAddressBookRef addressbook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressbook);
CFIndex numPeople = ABAddressBookGetPersonCount(addressbook);
for (int i=0; i < numPeople; i++) {
ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
ABMutableMultiValueRef phonelist = ABRecordCopyValue(person, kABPersonPhoneProperty);
CFIndex numPhones = ABMultiValueGetCount(phonelist);
for (int j=0; j < numPhones; j++) {
CFTypeRef ABphone = ABMultiValueCopyValueAtIndex(phonelist, j);
NSString *personPhone = (NSString *)ABphone;
NSLog(#"i am:");
personPhone =[personPhone stringByReplacingOccurrencesOfString:#"-"withString:#""];
personPhone=[personPhone stringByReplacingOccurrencesOfString:#")"withString:#""];
personPhone=[personPhone stringByReplacingOccurrencesOfString:#" "withString:#""];
personPhone=[personPhone stringByReplacingOccurrencesOfString:#"("withString:#""];
personPhone=[personPhone stringByReplacingOccurrencesOfString:#"+"withString:#""];
NSLog(#"xcxcxcxc");
CFRelease(ABphone);
if ( [personPhone isEqualToString:phoneNO] ){
NSString *aContactfirstName = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty) ;
NSString *aContactLastName = (NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty) ;
if ( aContactLastName != NULL && aContactfirstName != NULL){
aContactName = [NSString stringWithFormat:#"%# %#",aContactfirstName,aContactLastName];
}
else if(aContactfirstName != NULL){
aContactName = aContactfirstName;
}
else if(aContactLastName != NULL){
aContactName = aContactLastName;
}
if ( aContactfirstName){
CFRelease(aContactfirstName);
}
if (aContactLastName){
CFRelease(aContactLastName);
}
break;
}
}
CFRelease(phonelist);
}
CFRelease(allPeople);
CFRelease(addressbook);
return aContactName;
}
Use -
NSString *aContactfirstName = [(NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty) autorelease];
NSString *aContactLastName = [(NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty) autorelease];
if(aContactLastName != NULL){
aContactName = aContactLastName;//aContactName pointing to aContactLastName
}
In this you are assigning aContactLastName to aContactName(aContactLastName and aContactName are pointing to same memory location). and after that you are releasing aContactLastName.
if (aContactLastName){
CFRelease(aContactLastName);
}
and then you are returning return aContactName; (aContactName is already released)
this is wrong.
remove
if (aContactLastName){
CFRelease(aContactLastName);
}
from your code and return [aContactName autorelease];

iPhone address book problem

I'm having a bit of an issue with using the address book to get the names of the contacts from the device into my own contacts view within my application.
The code I have works fine on the emulator but I when tested on an iPhone 4 it will crash, the application seems to work fine if there are two or less contacts but 3 or more and the application crashes.
Here is the code I am using to get the names of contacts into an array.
ABAddressBookRef addressBook;
bool wantToSaveChanges = YES;
bool didSave;
CFErrorRef error = NULL;
addressBook = ABAddressBookCreate();
listOfContacts = [[NSMutableArray alloc]init];
int i;
int len = (int) ABAddressBookGetPersonCount(addressBook);
for(i = 1; i< (len+1); i++){
ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressBook, (ABRecordID) i);
NSString* name = (NSString *)ABRecordCopyCompositeName(person);
ABMultiValueRef number = (NSString *)ABRecordCopyValue(person,kABPersonPhoneProperty);
NSString *mobileNum = (NSString *)ABMultiValueCopyValueAtIndex(number, 0 );
NSLog(#"Name = %#", name);
NSLog(#"Number = %#", mobileNum);
[listOfContacts addObject:name];
[name release];
[mobileNum release];
}
if(ABAddressBookHasUnsavedChanges(addressBook)){
if(wantToSaveChanges){
didSave = ABAddressBookSave(addressBook, &error);
if(!didSave){
//Error
}
}
else{
ABAddressBookRevert(addressBook);
}
}
When it crashes this is the line that gets highlighted in Xcode:
NSString* name = (NSString *)ABRecordCopyCompositeName(person);
And the error states:
Thread 1: Program received signal: "EXC_BAD_ACCESS"
Can anyone see what the problem might be? I dont understand why it would work on the emulator but not on the device? And also why it works for up to two contacts but not 3 or more??
Just a guess:
ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressBook, (ABRecordID) i);
This line looks fishy for me. I doubt that the record IDs are numbered from 1 to whatever. Especially if you have deleted an entry.
This would explain why it works on the simulator, I guess you just added some test contacts and never deleted one.
Here is how I solved it:
(Note how I make sure to call only active records, also I created a customized Contact class)
This code takes care of edge case like: email/phone doesn't exist, or exists more than once...
+(NSArray *)getAddressBook{
ABAddressBookRef addressBook;
bool wantToSaveChanges = YES;
bool didSave;
CFErrorRef error = NULL;
addressBook = ABAddressBookCreate();
NSMutableArray *listOfContacts = [[NSMutableArray alloc]init];
CFArrayRef array=ABAddressBookCopyArrayOfAllPeople(addressBook);
int len=CFArrayGetCount(array);
for (int i = 0; i<len; i++){
ABRecordRef person = CFArrayGetValueAtIndex(array, i);
if (ABRecordGetRecordType(person)==kABPersonType){
NSString *firstName = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString *lastName = (NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
ABMultiValueRef emails = (ABMultiValueRef)ABRecordCopyValue(person,kABPersonEmailProperty);
ABMultiValueRef numbers = (ABMultiValueRef)ABRecordCopyValue(person,kABPersonPhoneProperty);
int sumEmails=ABMultiValueGetCount(emails);
int sumNumbers=ABMultiValueGetCount(numbers);
for (int j=0; j<(sumNumbers>sumEmails?sumNumbers:sumEmails); j++) {
ACL_AB_Contact *contact=[[ACL_AB_Contact alloc]initWithFirstName:firstName LastName:lastName];
if (j<sumEmails){
contact.emailAddress=(NSString *)ABMultiValueCopyValueAtIndex(emails,j);
}
if (j<sumNumbers){
contact.phoneNumber=(NSString *)ABMultiValueCopyValueAtIndex(numbers,j);
}
[contact logContact];
[listOfContacts addObject:contact];
[contact release];
}
}
}
if(ABAddressBookHasUnsavedChanges(addressBook)){
if(wantToSaveChanges){
didSave = ABAddressBookSave(addressBook, &error);
if(!didSave){
//Error
}
}
else{
ABAddressBookRevert(addressBook);
}
}
return [listOfContacts autorelease];
}
The record IDs are dynamic. It means that if you add 2 contacts and then remove the first, you will have only a contact with id "2". So I wouln't use a for statement to get through the contacts. Follow the Address Book Programming Guide

iPhone SDK Accessing Address book company contact

I have been able to use the SDK to access Address Book contacts for people, but whenever I pick a contact who is a company, my app crashes.
does anyone know the property for the company field?
does anyone know the code to make it work?
thanks in advance
It seems your issue is not related to company tag itself. AB fields need to be managed carefully, released when not used and checked for nil all the time, many fields are not set.
In principle, here is example of how I use it. This function loads contacts (those fields interested for my app) and returns array with contacts to the caller. Hope this is helpful. Note how I release not needed refs.
- (NSArray *)loadContacts
{
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
NSMutableArray *contacts = [NSMutableArray array];
for (int i = 0 ; i < nPeople ; i++ ) {
ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
NSString *firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString *lastName = ABRecordCopyValue(person, kABPersonLastNameProperty);
NSString *fullName;
if (firstName && lastName) {
fullName = [NSString stringWithFormat:#"%# %#", firstName, lastName];
} else {
if (firstName) {
fullName = [NSString stringWithString:firstName];
} else if (lastName) {
fullName = [NSString stringWithString:lastName];
} else {
continue;
}
}
NSString *email = nil;
ABMultiValueRef emails = ABRecordCopyValue(person, kABPersonEmailProperty);
if (emails) {
NSArray *emailAddresses = [(NSArray *)ABMultiValueCopyArrayOfAllValues(emails) autorelease];
if (emailAddresses && [emailAddresses count] > 0)
email = [emailAddresses objectAtIndex:0];
CFRelease(emails);
}
if (email) {
NSDictionary *contact = [NSDictionary
dictionaryWithObjectsAndKeys:fullName, #"name",
email, #"email", nil];
[contacts addObject:contact];
}
if (firstName)
CFRelease(firstName);
if (lastName)
CFRelease(lastName);
}
CFRelease(allPeople);
CFRelease(addressBook);
return contacts;
}
you need to use kABPersonOrganizationProperty property for get the company name from addressbook