Find out memory leak? - iphone

i am new on iphone apps.Now this is my first app,app is installed but not run?
I write this code it shows memory leak.please find out.Thanks in advance.
ABRecordRef ref = CFArrayGetValueAtIndex(all, i);
CFStringRef *firstName = (CFStringRef *)ABRecordCopyValue(ref, kABPersonFirstNameProperty);
NSLog(#"Name %#", firstName);
contact.strFirstName = (NSString*)firstName;
CFStringRef *lastName = (CFStringRef *)ABRecordCopyValue(ref, kABPersonLastNameProperty);
NSLog(#"Name %#", lastName);
contact.strLastName = (NSString*)lastName;
contact.contactName = [NSString stringWithFormat:#"%# %#",(NSString *)firstName,lastName];
NSLog(#"Name %#", contact.contactName);
ABMutableMultiValueRef phoneNumbers = ABRecordCopyValue(ref, kABPersonPhoneProperty);
for(CFIndex j = 0; j < ABMultiValueGetCount(phoneNumbers); j++)
{
CFStringRef phoneNumberRef = ABMultiValueCopyValueAtIndex(phoneNumbers, j);
NSString *phoneNumber = (NSString *) phoneNumberRef;
contact.strMobileNo = phoneNumber;
NSLog(#"phoneNO is %#", phoneNumber);
CFRelease(phoneNumberRef);
}
ABMultiValueRef emails = ABRecordCopyValue(ref, kABPersonEmailProperty);
for(CFIndex k = 0; k < ABMultiValueGetCount(emails); k++)
{
CFStringRef emailRef = ABMultiValueCopyValueAtIndex(emails, k);
NSString *mailid = (NSString *) emailRef;
contact.strMail = mailid;
NSLog(#"Email is %#", mailid);
CFRelease(emailRef);
}
CFRelease(emails);
CFRelease(phoneNumbers);

You are using ABRecordCopyValue on firstName and lastName which means you need to CFRelease those as well.

CFRelease is a way to go (as #Joe and #jamapag already answered).. I would just like to add that XCode has few nice features like cmd + shift + a gives u a static memory analyser.. And you can also use run -> run w/ performance tools and then use allocations or leaks to analyse our memory management dynamically.

You need to add:
CFRelease(firstName);
CFRelease(lastName);

Related

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.

how to write .csv file from function?

Hey Friends i got all contacts detail of my iphone by using this function ..
-(void)collectContacts
{
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef people = ABAddressBookCopyArrayOfAllPeople(addressBook);
//NSLog(#" the Name %#%",people);
for(int i = 0;i<ABAddressBookGetPersonCount(addressBook);i++)
{
ABRecordRef ref = CFArrayGetValueAtIndex(people, i);
// Get First name, Last name, Prefix, Suffix, Job title
NSString *firstName = (NSString *)ABRecordCopyValue(ref,kABPersonFirstNameProperty);
NSString *lastName = (NSString *)ABRecordCopyValue(ref,kABPersonLastNameProperty);
NSString *prefix = (NSString *)ABRecordCopyValue(ref,kABPersonPrefixProperty);
NSString *suffix = (NSString *)ABRecordCopyValue(ref,kABPersonSuffixProperty);
NSString *jobTitle = (NSString *)ABRecordCopyValue(ref,kABPersonJobTitleProperty);
NSLog(#" the phoneType %#%",firstName);
NSLog(#" the phoneType %#%",lastName);
ABMultiValueRef phones = ABRecordCopyValue(ref, kABPersonPhoneProperty);
for(CFIndex j = 0; j < ABMultiValueGetCount(phones); j++)
{
CFStringRef phoneNumberRef = ABMultiValueCopyValueAtIndex(phones, j);
NSString *phoneLabel =(NSString*) ABAddressBookCopyLocalizedLabel (ABMultiValueCopyLabelAtIndex(phones, j));
NSString *phoneNumber = (NSString *)phoneNumberRef;
NSLog(#" the phoneType %#%",phoneLabel);
NSLog(#" the phoneNumber %#%",phoneNumber);
}
CFStringRef address;
CFStringRef label;
ABMutableMultiValueRef multi = ABRecordCopyValue(ref, kABPersonAddressProperty);
for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++)
{
label = ABMultiValueCopyLabelAtIndex(multi, i);
CFStringRef readableLabel = ABAddressBookCopyLocalizedLabel(label);
NSLog(#" Lable %#%",readableLabel);
address = ABMultiValueCopyValueAtIndex(multi, i);
NSLog(#" Address %#%",address);
CFRelease(address);
CFRelease(label);
}
ABMultiValueRef emails = ABRecordCopyValue(ref, kABPersonEmailProperty);
for(CFIndex idx = 0; idx < ABMultiValueGetCount(emails); idx++)
{
CFStringRef emailRef = ABMultiValueCopyValueAtIndex(emails, idx);
NSString *strLbl = (NSString*) ABAddressBookCopyLocalizedLabel (ABMultiValueCopyLabelAtIndex (emails, idx));
NSLog(#" Email Lable %#%",strLbl);
NSString *strEmail_old = (NSString*)emailRef;
NSLog(#" Email-Id %#%",strEmail_old);
//[[strEmail_old componentsJoinedByString:#","] writeToFile:#"components.csv" atomically:YES encoding:NSUTF8StringEncoding error:NULL];
}
}
//[[ContactsText componentsJoinedByString:#","] writeToFile:#"components.csv" atomically:YES encoding:NSUTF8StringEncoding error:NULL];
// NSLog(#" Data in the .CSV file = %#%",ContactsText);
}
'
Now i want to make .csv file from this function's output .. and m getting all data in NSLog . I juat want to write .csv file from that data .. Can anyone help me in that ?? Data coming are proper but .csv file not gonna written ...Thanks
Assuming you will have all the data in "ContactsText", try following code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* savePath = [paths objectAtIndex:0];
savePath = [savePath stringByAppendingPathComponent:#"components.csv"];
[[ContactsText componentsJoinedByString:#","] writeToFile:savePath atomically:YES encoding:NSUTF8StringEncoding error:NULL];
Remember that you cannot just save "components.csv" file. You have to save the file in documents folder only.
There are many Open Source extensions that add csv support to arrays. For example CHCSVParser which is available on GitHub.
Notice that your data may contain characters that require special treatment - in the case of a CSV file most notably the comma itself. If there is a comma in the string you write out, you should put double quotes around that field. In that case, if there is already a double quote in the string, you need to escape that, too.
I would suggest that you use the CHCSVParser from Dave DeLong, you can find it here: http://davedelong.com/portfolio
It is worth the trouble to import a good third-party framework to make sure edge cases are handled correctly.

app crashes when using kABPersinPhoneProperty

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!!

How to retrieve mobile numbers from iPhone Contacts.

I use the following code to set the retrieve the phone number in my app.
CFStringRef addressBookMobile;
ABRecordRef person;
NSString *mobile;
person = CFArrayGetValueAtIndex(people, i);
addressBookMobile = ABRecordCopyValue(person, kABPersonPhoneProperty);
mobile = [NSString stringWithFormat:#"%#", addressBookMobile];
The tag of the contacts is 'mobile'. However, when I use the NSLog(#"%#", mobile); . It displays the <NSCFType: 0x802ffc0>. does any problem for my code?
Should I use the const CFStringRef kABPersonPhoneMobileLabel and how to use? As if I replace it as the above code, it has the error. Can anyone help me? Thank you.
check the ABPerson Refrence and You need't use #"$!!$" but kABPersonPhoneMobileLabel. the example is:
ABMultiValueRef phones = (ABMultiValueRef)ABRecordCopyValue(person, kABPersonPhoneProperty);
NSString* mobile=#"";
NSString* mobileLabel;
for (int i=0; i < ABMultiValueGetCount(phones); i++) {
//NSString *phone = (NSString *)ABMultiValueCopyValueAtIndex(phones, i);
//NSLog(#"%#", phone);
mobileLabel = (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 release];
mobile = (NSString*)ABMultiValueCopyValueAtIndex(phones, i);
NSLog(#"%#", mobile);
}
The phone numbers of a person in the Address Book are in the form of a multi-value property.
In your case, you should have something like the following (haven't tried it, typing directly here, so I don't know if it compiles and/or works):
ABMultiValueRef phoneNumbers = (NSString *)ABRecordCopyValue(person, kABPersonPhoneProperty);
NSString *mobileNumber;
NSString *mobileLabel;
for (CFIndex i = 0; i < ABMultiValueGetCount(phoneNumbers); i++) {
mobileLabel = (NSString *)ABMultiValueCopyLabelAtIndex(mobilePhones, i);
if ([mobileLabel isEqualToString:#"mobile"]) {
mobileNumber = (NSString*)ABMultiValueCopyValueAtIndex(mobilePhones,i);
break;
}
}
ABMultiValueRef phoneNumbers = (NSString *)ABRecordCopyValue(person, kABPersonPhoneProperty);
CRStringRef mobileNumber;
CRStringRef mobileLabel;
for (CFIndex i = 0; i < ABMultiValueGetCount(phoneNumbers); i++) {
mobileLabel = ABMultiValueCopyLabelAtIndex(phoneNumbers, i);
if ([mobileLabel isEqualToString:#"_$!<Mobile>!$_"]) {
mobileNumber = ABMultiValueCopyValueAtIndex(phoneNumbers,i);
break;
}
}
This is solid for ARC 64bit iOS8:
- (NSArray *)phoneNumbersOfContactAsStrings:(ABRecordRef)contactRef {
NSMutableArray *mobilePhones = [NSMutableArray arrayWithCapacity:0];
ABMultiValueRef phones = ABRecordCopyValue(contactRef, kABPersonPhoneProperty);
NSArray *allPhoneNumbers = (NSArray *)CFBridgingRelease(ABMultiValueCopyArrayOfAllValues(phones));
for (NSUInteger i=0; i < [allPhoneNumbers count]; i++) {
if ([(NSString *)CFBridgingRelease(ABMultiValueCopyLabelAtIndex(phones, (long)i)) isEqualToString:(NSString *)kABPersonPhoneMobileLabel]) {
[mobilePhones addObject:CFBridgingRelease(ABMultiValueCopyValueAtIndex(phones, (long)i))];
}
if ([(NSString *)CFBridgingRelease(ABMultiValueCopyLabelAtIndex(phones, (long)i)) isEqualToString:(NSString *)kABPersonPhoneIPhoneLabel]) {
[mobilePhones addObject:CFBridgingRelease(ABMultiValueCopyValueAtIndex(phones, (long)i))];
}
}
CFRelease(phones);
return mobilePhones;
}

Getting iPhone addressbook contents without GUI

I would like to list all phone numbers (or any other field) of people in the addressbook.
I've written the following code:
- (void)addressBookFill{
ABAddressBookRef addressBook = ABAddressBookCreate();
people = (NSArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);
[addressBook release];
}
- (void)printAddressBook{
for(id person in people){
NSLog(#"%#", [person class]);
NSLog(#"\t%#", person );
}
}
When I invoke the printAddressBook method I get this on my console:
2010-07-06 10:34:11.998 app[91420:207] __NSCFType
2010-07-06 10:34:11.999 app[91420:207] <CPRecord: 0x5d56ce0 ABPerson>
And I don't have any idea, how to dereference this ABPerson object, how to get any info from it.
I tried:
firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
but I got some exceptions.
Can anybody tell me how to get some info from these objects?
Read the documentation about the ABPerson class:
http://developer.apple.com/mac/library/documentation/UserExperience/Reference/AddressBook/Classes/ABPerson_Class/Reference/Reference.html
and also the ABRecord class:
http://developer.apple.com/mac/library/documentation/UserExperience/Reference/AddressBook/Classes/ABRecord_Class/Reference/Reference.html#//apple_ref/occ/cl/ABRecord
[ person valueForProperty: #"propName" ]
You can get the available properties with:
[ ABPerson properties ]
[ EDIT ]
On iPhone, you can use the following code to access a value:
NSString * lastName = (NSString *)ABRecordCopyValue( person, kABPersonLastNameProperty );
May be this code will help you for iOS5, please like it
ABAddressBookRef addressBook = ABAddressBookCreate();
NSArray *arrayOfAllPeople = (__bridge_transfer NSArray *) ABAddressBookCopyArrayOfAllPeople(addressBook);
NSUInteger peopleCounter = 0;
for (peopleCounter = 0;peopleCounter < [arrayOfAllPeople count]; peopleCounter++){
ABRecordRef thisPerson = (__bridge ABRecordRef) [arrayOfAllPeople objectAtIndex:peopleCounter];
NSString *name = (__bridge_transfer NSString *) ABRecordCopyCompositeName(thisPerson);
NSLog(#"First Name = %#", name);
ABMultiValueRef emails = ABRecordCopyValue(thisPerson, kABPersonEmailProperty);
for (NSUInteger emailCounter = 0; emailCounter < ABMultiValueGetCount(emails); emailCounter++){
/* And then get the email address itself */
NSString *email = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(emails, emailCounter);
NSLog(#"Email : %#",email);
}
}
CFRelease(addressBook);
You want get only those contact who has email on my contact so use this code for iOS5
Please like it if it work
First add AddressBook.framework and #import <AddressBook/AddressBook.h>
- (NSArray*)printAddressBook{
NSMutableArray *mutableData = [NSMutableArray new];
ABAddressBookRef addressBook = ABAddressBookCreate();
NSArray *arrayOfAllPeople = (__bridge_transfer NSArray *) ABAddressBookCopyArrayOfAllPeople(addressBook);
NSUInteger peopleCounter = 0;
for (peopleCounter = 0;peopleCounter < [arrayOfAllPeople count]; peopleCounter++){
ABRecordRef thisPerson = (__bridge ABRecordRef) [arrayOfAllPeople objectAtIndex:peopleCounter];
NSString *name = (__bridge_transfer NSString *) ABRecordCopyCompositeName(thisPerson);
NSLog(#"First Name = %#", name);
ABMultiValueRef emails = ABRecordCopyValue(thisPerson, kABPersonEmailProperty);
for (NSUInteger emailCounter = 0; emailCounter < ABMultiValueGetCount(emails); emailCounter++){
/* And then get the email address itself */
NSString *email = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(emails, emailCounter);
NSLog(#"Email : %#",email);
NSMutableDictionary *personDict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:name,#"name",email,#"email", nil];
[mutableData addObject:personDict];
}
}
CFRelease(addressBook);
return [NSArray arrayWithArray:mutableData];
}