I'm having some memory leaks with both ABAddressBookGetPersonWithRecordID and ABPersonSetImageData. I've been looking for solutions before posting here but I still don't understand. If I play quite a long time with the iPhone 3GS or with only a few contacts with iPhone 3G, actually the application crashes. Here is my code in the didSelectRowAtIndexPath method. I've seen sample codes with these methods and I don't see what I'm missing. Thank you in advance. (sorry for mistakes...)
Contact *myContact = [fetchedResultsController objectAtIndexPath:indexPath];
cancelCreateContact = NO;
ABAddressBookRef ab = ABAddressBookCreate();
int len = ABAddressBookGetPersonCount(ab);
ABRecordID contactID;
ABRecordRef person;
BOOL alreadyExists = NO;
CFStringRef first, last;
for(int i = 1; i < (len + 1); i++)
{
person = ABAddressBookGetPersonWithRecordID(ab, (ABRecordID)i);
if(!person){
len++;
continue;
}
first = ABRecordCopyValue(person, kABPersonFirstNameProperty);
last = ABRecordCopyValue(person, kABPersonLastNameProperty);
if ([[(NSString*)first lowercaseString] isEqualToString:[myContact.firstname lowercaseString]] && [[(NSString*)last lowercaseString] isEqualToString:[myContact.lastname lowercaseString]]) {
alreadyExists = YES;
contactID = ABRecordGetRecordID(person);
break;
}
}
if (alreadyExists) {
//NSLog(#"already exists");
ABRecordRef aContactFound = ABAddressBookGetPersonWithRecordID(ab, contactID);
ABRecordRef aRecord = ABPersonCreate();
CFErrorRef anError = NULL;
CFStringRef firstname = ABRecordCopyValue(aContactFound, kABPersonFirstNameProperty);
ABRecordSetValue(aRecord, kABPersonFirstNameProperty, firstname, &anError);
CFRelease(firstname);
CFStringRef lastname = ABRecordCopyValue(aContactFound, kABPersonLastNameProperty);
ABRecordSetValue(aRecord, kABPersonLastNameProperty, lastname, &anError);
CFRelease(lastname);
CFStringRef job = ABRecordCopyValue(aContactFound, kABPersonJobTitleProperty);
ABRecordSetValue(aRecord, kABPersonJobTitleProperty, job, &anError);
CFRelease(job);
ABMultiValueRef instantMessage = ABRecordCopyValue(aContactFound, kABPersonInstantMessageProperty);
ABRecordSetValue(aRecord, kABPersonInstantMessageProperty, instantMessage, &anError);
CFRelease(instantMessage);
ABMultiValueRef phone = ABRecordCopyValue(aContactFound, kABPersonPhoneProperty);
ABRecordSetValue(aRecord, kABPersonPhoneProperty, phone, &anError);
CFRelease(phone);
ABMultiValueRef email = ABRecordCopyValue(aContactFound, kABPersonEmailProperty);
ABRecordSetValue(aRecord, kABPersonEmailProperty, email, &anError);
CFRelease(email);
CFDataRef imageData = ABPersonCopyImageData(aContactFound);
ABPersonSetImageData(aRecord, imageData, &anError);
ABAddressBookSave(ab, &anError);
CFRelease(imageData);
ABUnknownPersonViewController *ABView = [[ABUnknownPersonViewController alloc] init];
ABView.unknownPersonViewDelegate = self;
ABView.displayedPerson = aRecord;
ABView.allowsAddingToAddressBook = NO;
ABView.allowsActions = YES;
ABView.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:ABView animated:YES];
[ABView release];
CFRelease(aRecord);
}else{
//NSLog(#"doesn't exist");
//sinon ouvre une fiche pré-remplie
ABRecordRef aRecord = ABPersonCreate();
CFErrorRef anError = nil;
if(![myContact.firstname isEqualToString:#""]) ABRecordSetValue(aRecord, kABPersonFirstNameProperty, myContact.firstname, &anError);
if(![myContact.lastname isEqualToString:#""]) ABRecordSetValue(aRecord, kABPersonLastNameProperty, myContact.lastname, &anError);
if(![myContact.email isEqualToString:#""]) {
ABMultiValueRef ABemail = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMultiValueAddValueAndLabel(ABemail, myContact.email, kABWorkLabel, NULL);
ABRecordSetValue(aRecord, kABPersonEmailProperty, ABemail, &anError);
CFRelease(ABemail);
}
if(![myContact.phone_business isEqualToString:#""] || ![myContact.phone_mobile isEqualToString:#""]){
ABMultiValueRef ABphones = ABMultiValueCreateMutable(kABMultiStringPropertyType);
if(![myContact.phone_business isEqualToString:#""]) ([myContact.phone_business stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]].length == 4 || [myContact.phone_business stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]].length == 5) ? ABMultiValueAddValueAndLabel(ABphones, [NSString stringWithFormat:#"014443%#", myContact.phone_business], kABPersonPhoneMainLabel, NULL) : ABMultiValueAddValueAndLabel(ABphones, myContact.phone_business, kABPersonPhoneMainLabel, NULL);
if(![myContact.phone_mobile isEqualToString:#""] && ([myContact.phone_mobile stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]].length == 10)) ABMultiValueAddValueAndLabel(ABphones, myContact.phone_mobile, kABPersonPhoneMobileLabel, NULL);
ABRecordSetValue(aRecord, kABPersonPhoneProperty, ABphones, &anError);
CFRelease(ABphones);
}
if(![myContact.job isEqualToString:#""]) ABRecordSetValue(aRecord, kABPersonJobTitleProperty, myContact.job, &anError);
if(![myContact.msn isEqualToString:#""] || ![myContact.twitter isEqualToString:#""] || ![myContact.facebook isEqualToString:#""]){
ABMultiValueRef ABmessaging = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType);
NSMutableDictionary *dMessaging;
if(![myContact.msn isEqualToString:#""]){
dMessaging = [[NSMutableDictionary alloc] init];
[dMessaging setObject:myContact.msn forKey:(NSString *) kABPersonInstantMessageUsernameKey];
[dMessaging setObject:#"MSN" forKey:(NSString *)kABPersonInstantMessageServiceKey];
ABMultiValueAddValueAndLabel(ABmessaging, dMessaging, kABPersonInstantMessageServiceMSN, NULL);
[dMessaging release];
}
if(![myContact.twitter isEqualToString:#""]){
dMessaging = [[NSMutableDictionary alloc] init];
[dMessaging setObject:myContact.twitter forKey:(NSString *) kABPersonInstantMessageUsernameKey];
[dMessaging setObject:#"Twitter" forKey:(NSString *)kABPersonInstantMessageServiceKey];
ABMultiValueAddValueAndLabel(ABmessaging, dMessaging, kABOtherLabel, NULL);
[dMessaging release];
}
if(![myContact.facebook isEqualToString:#""]){
dMessaging = [[NSMutableDictionary alloc] init];
[dMessaging setObject:myContact.facebook forKey:(NSString *) kABPersonInstantMessageUsernameKey];
[dMessaging setObject:#"Facebook" forKey:(NSString *)kABPersonInstantMessageServiceKey];
ABMultiValueAddValueAndLabel(ABmessaging, dMessaging, kABOtherLabel, NULL);
[dMessaging release];
}
ABRecordSetValue(aRecord, kABPersonInstantMessageProperty, ABmessaging, &anError);
CFRelease(ABmessaging);
}
//pas dans l'XMLToObjectParser parce que ça prenait une plombe...
NSURL *url = [NSURL URLWithString:myContact.picture_path];
NSData *data = [NSData dataWithContentsOfURL:url];
if(!data){
NSString *picture_path = (![myContact.gender isEqualToString:#""]) ? [NSString stringWithFormat:#"default_%#_head.png", [myContact.gender lowercaseString]] : #"default_m_head.png";
[myContact setPicture_path:picture_path];
NSError *error = nil;
if(![self.managedObjectContext save:&error]){
NSLog(#"pb lors de l'enregistrement de picture path");
}
//NSData *localData = [NSData dataWithContentsOfFile:myContact.picture_path];
UIImage *image = [UIImage imageNamed:picture_path];
NSData *localData = UIImagePNGRepresentation(image);
CFDataRef cfLocalData = CFDataCreate(NULL, [localData bytes], [localData length]);
ABPersonSetImageData(aRecord, cfLocalData, &anError);
ABAddressBookSave(ab, &anError);
CFRelease(cfLocalData);
}else {
UIImage *image = [UIImage imageWithData:data];
NSString *extension = [(NSArray*)[myContact.picture_path componentsSeparatedByString:#"."] objectAtIndex:1];
NSData *localData = ([extension isEqualToString:#"png"]) ? UIImagePNGRepresentation(image) : UIImageJPEGRepresentation(image, 1.0f);
CFDataRef cfLocalData = CFDataCreate(NULL, [localData bytes], [localData length]);
ABPersonSetImageData(aRecord, cfLocalData, &anError);
ABAddressBookSave(ab, &anError);
CFRelease(cfLocalData);
}
if (anError != nil) { NSLog(#"error :: %#", anError); }
ABUnknownPersonViewController *ABView = [[ABUnknownPersonViewController alloc] init];
ABView.unknownPersonViewDelegate = self;
ABView.displayedPerson = aRecord;
ABView.allowsAddingToAddressBook = YES;
ABView.allowsActions = YES;
ABView.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:ABView animated:YES];
[ABView release];
CFRelease(aRecord);
}
CFRelease(ab);
Firstly: read up on your Core Foundation memory management. You don't yet know the rules by heart.
Secondly: when a CF-friendly function has "Copy" in the name, you must check its result for NULL, and release that result when done if it's not NULL. So this:
first = ABRecordCopyValue(person, kABPersonFirstNameProperty);
Will become a memory leak if it's never followed by CFRelease(first);.
Thirdly: if a Core Foundation value is NULL, passing it to CFRelease will crash:
CFStringRef firstname = ABRecordCopyValue(aContactFound, kABPersonFirstNameProperty);
ABRecordSetValue(aRecord, kABPersonFirstNameProperty, firstname, &anError);
CFRelease(firstname);
If firstname is NULL (which it could be--imagine a contact named simply "Smith") then a crash will happen.
Related
I am not able to retrieve mobile number from below code, i am trying lots of thing but unable to solve it. please help me
//this below code is for saving mobile number and phone number
ABRecordRef newPerson = ABPersonCreate();
ABMultiValueAddValueAndLabel(phone, (__bridge CFTypeRef)(txtMob2.text), kABHomeLabel, NULL);
ABRecordSetValue(newPerson, kABPersonPhoneProperty, phone, &error);
//image
NSData *dataref = UIImagePNGRepresentation(imgProfile.image);
ABPersonSetImageData(newPerson, (__bridge CFDataRef)(dataref), &error);
ABAddressBookAddRecord(addressbook, newPerson, &error);
ABAddressBookSave(addressbook, nil);
CFRelease(newPerson);
// Now Below code is of displaying details.
- (void)displayContacts
{
int i;
appDelegate.arr_contact = [[NSMutableArray alloc] init];
ABAddressBookRef contactBook =ABAddressBookCreateWithOptions(nil, NULL);
NSArray *allData = (__bridge_transfer NSArray *)(ABAddressBookCopyArrayOfAllPeople(contactBook));
NSUInteger contactNum = 0;
NSInteger recordId;
ABRecordRef recId;
for (i =0; i < [allData count]; i++)
{
appDelegate.dict_contact =[[NSMutableDictionary alloc] init];
ABRecordRef ref =(__bridge ABRecordRef)(allData[i]);
//mobile no and phone no
ABMultiValueRef mobNum = ABRecordCopyValue(ref, kABPersonPhoneProperty);
CFIndex PhoneCount = ABMultiValueGetCount(mobNum);
for (int k = 0; k <PhoneCount; k++) {
strMobile = (__bridge NSString *)(ABMultiValueCopyLabelAtIndex(mobNum, k));
strPhone = (__bridge NSString *)(ABMultiValueCopyValueAtIndex(mobNum, k));
if ([strMobile isEqualToString:(NSString *)kABPersonPhoneMobileLabel])
{
mobileno = (__bridge NSString*)ABMultiValueCopyValueAtIndex(mobNum, k);
}
else if ([strPhone isEqualToString:(NSString *)kABHomeLabel])
{
phoneno = (__bridge NSString*)ABMultiValueCopyValueAtIndex(mobNum, k);
break;
}
NSLog(#"Mobile: %# phone: %#, %#",mobileno, phoneno, strPhone);
[appDelegate.dict_contact setObject:[NSString stringWithFormat:#"%#",mobileno] forKey:#"mobno"];
[appDelegate.dict_contact setObject:[NSString stringWithFormat:#"%#",phoneno] forKey:#"phnno"];
}
//image
NSData *imgData = (__bridge NSData *)ABPersonCopyImageDataWithFormat(ref, kABPersonImageFormatThumbnail);
UIImage *image;
if (imgData)
{
image = [UIImage imageWithData:imgData];
NSLog(#"add image: %#",image);
}else
{
image = [UIImage imageNamed:#"dummy.png"];
}
[appDelegate.dict_contact setObject:image forKey:#"image"];
[appDelegate.arr_contact addObject:appDelegate.dict_contact];
}
}
Please check my edited code.
Please See this code....
-(void)GetAddressBook
{
Contacts = [[NSMutableArray alloc]init];
if (ABAddressBookCreateWithOptions) {
#try {
ABAddressBookRef addressBook = ABAddressBookCreate();
// NSArray *people = (NSArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);
if (!addressBook) {
NSLog(#"opening address book");
}
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
NSLog(#"opening address book ==%ld",nPeople);
for (int i=0;i < nPeople;i++) {
NSMutableDictionary *dOfPerson=[NSMutableDictionary dictionary];
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople,i);
NSString *Contact;
ABMultiValueRef phones =(__bridge ABMultiValueRef)((__bridge NSString*)ABRecordCopyValue(ref, kABPersonPhoneProperty));
CFStringRef firstName, lastName;
NSMutableArray *array = [[NSMutableArray alloc]init];
NSString *email;
firstName = ABRecordCopyValue(ref, kABPersonFirstNameProperty);
lastName = ABRecordCopyValue(ref, kABPersonLastNameProperty);
ABMultiValueRef multiValueRef = ABRecordCopyValue(ref, kABPersonEmailProperty);
array = [(__bridge NSMutableArray *)ABMultiValueCopyArrayOfAllValues(multiValueRef) mutableCopy];
email = ([array count] > 0) ? array[0] : #"";
if(firstName)
{
Contact = [NSString stringWithFormat:#"%#", firstName];
if(lastName)
Contact = [NSString stringWithFormat:#"%# %#",firstName,lastName];
}
[dOfPerson setObject:Contact forKey:#"name"];
[dOfPerson setObject:[NSString stringWithFormat:#"%d", i] forKey:#"id"];
[dOfPerson setObject:[NSString stringWithFormat:#"%#",#""] forKey:#"found"];
[dOfPerson setObject:email forKey:#"email"];
NSString* mobileLabel;
for(CFIndex j = 0; j< ABMultiValueGetCount(phones); j++)
{
mobileLabel = (__bridge NSString*)ABMultiValueCopyLabelAtIndex(phones, j);
if([mobileLabel isEqualToString:(NSString *)kABPersonPhoneMobileLabel])
{
[dOfPerson setObject:(__bridge NSString*)ABMultiValueCopyValueAtIndex(phones, j) forKey:#"Phone"];
}
else if ([mobileLabel isEqualToString:(NSString*)kABPersonPhoneIPhoneLabel])
{
[dOfPerson setObject:(__bridge NSString*)ABMultiValueCopyValueAtIndex(phones, j) forKey:#"Phone"];
break ;
}
}
[Contacts addObject:dOfPerson];
}
}
#catch (NSException * e) {
NSLog(#"Exception: %#", e);
}
dispatch_async(dispatch_get_main_queue(), ^{
});
Here you will get Phone number, First Name, Last name and Email Id. Here Contacts is an NSMutableArray. Also view this answer for a complete set of code.
contact details from ipad using objective-c
Try This In this code I'm getting both the name and mobile number if you want the mobile number only use this kABPersonPhoneProperty:
CFErrorRef * error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
for (int i=0;i < nPeople;i++)
{
NSString* name;
NSMutableDictionary* tempContactDic = [NSMutableDictionary new];
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople,i);
CFStringRef firstName;
firstName = ABRecordCopyValue(ref, kABPersonFirstNameProperty);
name = (__bridge NSString *)(firstName);
[tempContactDic setValue:name forKey:#"name"];
//fetch email id
NSString *strEmail;
NSMutableString* strMobile;
ABMultiValueRef email = ABRecordCopyValue(ref, kABPersonPhoneProperty);
CFStringRef tempEmailref = ABMultiValueCopyValueAtIndex(email, 0);
strEmail = (__bridge NSString *)tempEmailref;
strEmail = [strEmail stringByReplacingOccurrencesOfString:#"-" withString:#""];
strEmail = [strEmail stringByReplacingOccurrencesOfString:#"(" withString:#""];
strEmail = [strEmail stringByReplacingOccurrencesOfString:#")" withString:#""];
strEmail = [strEmail stringByReplacingOccurrencesOfString:#" " withString:#""];
strEmail = [strEmail stringByReplacingOccurrencesOfString:#"+" withString:#""];
strMobile = [[NSMutableString alloc] initWithString:strEmail];
if ([strEmail length] == 10) {
[strMobile insertString:#"91" atIndex:0];
}
else {
}
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber * myNumber = [f numberFromString:strMobile];
[tempContactDic setValue:myNumber forKey:#"phone"];
[contactsArray addObject:tempContactDic];
}
/// With below two steps of code you'll get the contacts in alphabetical order
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)];
[contactsArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
I am new to iphone App Development(using iOS6) and have been facing problem with fetching the mobile Numbers from the contact List into a UITableViewController. I can get the first name and last name correctly but the phone Numbers are being returned as null. I could not understand the reason behind this.What is it that I am doing wrong? My code is as follows:
NSMutableArray *people = (__bridge_transfer NSMutableArray *) ABAddressBookCopyArrayOfAllPeople (addressBookRef);
NSString *firstName = (__bridge_transfer NSString *)ABRecordCopyValue((__bridge ABRecordRef)([people objectAtIndex:indexPath.row]), kABPersonFirstNameProperty);
NSString *lastName = (__bridge_transfer NSString *)ABRecordCopyValue((__bridge ABRecordRef)([people objectAtIndex:indexPath.row]), kABPersonLastNameProperty);
ABMultiValueRef phoneNumbers = ABRecordCopyValue((__bridge ABRecordRef)([people objectAtIndex:indexPath.row]),kABPersonPhoneProperty);
if (([firstName isEqualToString:#""] || [firstName isEqualToString:#"(null)"] || firstName == nil) &&
([lastName isEqualToString:#""] || [lastName isEqualToString:#"(null)"] || lastName == nil))
{
// do nothing
}
else
{
aName = [NSString stringWithFormat:#"%# %#", firstName, lastName];
if ([firstName isEqualToString:#""] || [firstName isEqualToString:#"(null)"] || firstName == nil)
{
aName = [NSString stringWithFormat:#"%#", lastName];
}
if ([lastName isEqualToString:#""] || [lastName isEqualToString:#"(null)"] || lastName == nil)
{
aName = [NSString stringWithFormat:#"%#", firstName];
}
//[self.tableItems addObject:aName];
NSLog(#"%# added",aName);
}
//fetch multiple phone nos. and use only 0th
id person = people[indexPath.row];
ABMultiValueRef multi = ABRecordCopyValue((__bridge ABRecordRef)(person), kABPersonPhoneProperty);
NSString* phone = (__bridge NSString*)ABMultiValueCopyValueAtIndex(multi, 0);
NSLog(#"%#",phone);
[cell.detailTextLabel setText:phone];
[cell.textLabel setText:aName];
return cell;
Here this is a full working code
-(void)GetAddressBook
{
Contacts = [[NSMutableArray alloc]init];
if (ABAddressBookCreateWithOptions) {
#try {
ABAddressBookRef addressBook = ABAddressBookCreate();
// NSArray *people = (NSArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);
if (!addressBook) {
NSLog(#"opening address book");
}
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
NSLog(#"opening address book ==%ld",nPeople);
for (int i=0;i < nPeople;i++) {
NSMutableDictionary *dOfPerson=[NSMutableDictionary dictionary];
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople,i);
NSString *Contact;
ABMultiValueRef phones =(__bridge ABMultiValueRef)((__bridge NSString*)ABRecordCopyValue(ref, kABPersonPhoneProperty));
CFStringRef firstName, lastName;
NSMutableArray *array = [[NSMutableArray alloc]init];
NSString *email;
firstName = ABRecordCopyValue(ref, kABPersonFirstNameProperty);
lastName = ABRecordCopyValue(ref, kABPersonLastNameProperty);
ABMultiValueRef multiValueRef = ABRecordCopyValue(ref, kABPersonEmailProperty);
array = [(__bridge NSMutableArray *)ABMultiValueCopyArrayOfAllValues(multiValueRef) mutableCopy];
email = ([array count] > 0) ? array[0] : #"";
if(firstName)
{
Contact = [NSString stringWithFormat:#"%#", firstName];
if(lastName)
Contact = [NSString stringWithFormat:#"%# %#",firstName,lastName];
}
[dOfPerson setObject:Contact forKey:#"name"];
[dOfPerson setObject:[NSString stringWithFormat:#"%d", i] forKey:#"id"];
[dOfPerson setObject:[NSString stringWithFormat:#"%#",#""] forKey:#"found"];
[dOfPerson setObject:email forKey:#"email"];
NSString* mobileLabel;
for(CFIndex j = 0; j< ABMultiValueGetCount(phones); j++)
{
mobileLabel = (__bridge NSString*)ABMultiValueCopyLabelAtIndex(phones, j);
if([mobileLabel isEqualToString:(NSString *)kABPersonPhoneMobileLabel])
{
[dOfPerson setObject:(__bridge NSString*)ABMultiValueCopyValueAtIndex(phones, j) forKey:#"Phone"];
}
else if ([mobileLabel isEqualToString:(NSString*)kABPersonPhoneIPhoneLabel])
{
[dOfPerson setObject:(__bridge NSString*)ABMultiValueCopyValueAtIndex(phones, j) forKey:#"Phone"];
break ;
}
}
[Contacts addObject:dOfPerson];
}
}
#catch (NSException * e) {
NSLog(#"Exception: %#", e);
}
dispatch_async(dispatch_get_main_queue(), ^{
});
}
The Phone numbers are to be taken like ABMultiValueRef phones =(__bridge ABMultiValueRef)((__bridge NSString*)ABRecordCopyValue(ref, kABPersonPhoneProperty));
I am working on an iphone application that crashes where a user has a lot of contacts.Below is a function call that causes a crash, but only when a user has approx. more than 500 contacts.Below is a function call.Thanks in advance.
- (IBAction)addToAddressBook{
NSString *importString = [[NSString alloc] init];
importString = importTextView.text;
if (importString==nil) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Could not Find Text"
message:#"Try Pasting the Text Again"
delegate:nil
cancelButtonTitle:#"Cancel"
otherButtonTitles:nil];
[alert show];
[alert release];
}
statusLabel.text = #"Importing Lines";
NSArray *importLines = [importString componentsSeparatedByString:#"\n"];
[importString release];
ABAddressBookRef addressBook = ABAddressBookCreate();
CFRetain(addressBook);
ABRecordRef person;
CFErrorRef error = NULL;
ABMutableMultiValueRef multiPhone;
ABMutableMultiValueRef multiURL = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMutableMultiValueRef multiEmail = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMutableMultiValueRef multiAddress = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType);
ABMutableMultiValueRef multiDate = ABMultiValueCreateMutable(kABMultiStringPropertyType);
NSMutableDictionary *addressDictionary;
statusLabel.text = #"Counting Records";
int totalRecords = 0;
for( int j = 0; j < 5; j++){
NSString *line = [importLines objectAtIndex:j];
if ([line rangeOfString: #"Contacts:"].location!=NSNotFound) {
NSString *totalContactsLabel = [[line componentsSeparatedByString:#" Contacts: "] objectAtIndex:1];
totalRecords = [totalContactsLabel intValue];
}
}
int recordNumber = 0;
statusLabel.text = [NSString stringWithFormat:#"%i/%i", recordNumber, totalRecords];
for (NSString *line in importLines)
{
if (![line isEqualToString:#""])
{
NSMutableString *mutableLine = [NSMutableString stringWithString: line];
if ([line hasPrefix:#"---"]) {
//NSLog(#"starting new person");
person = ABPersonCreate();
multiPhone = ABMultiValueCreateMutable(kABMultiStringPropertyType); //clear multiphone for each new person
multiURL = ABMultiValueCreateMutable(kABMultiStringPropertyType);
multiEmail = ABMultiValueCreateMutable(kABMultiStringPropertyType);
multiDate = ABMultiValueCreateMutable(kABMultiStringPropertyType);
multiAddress = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType);
} else if ([line hasPrefix:#"First Name: "]) {
[mutableLine deleteCharactersInRange: [mutableLine rangeOfString: #"First Name: "]];
line = (NSString *)mutableLine;
ABRecordSetValue(person, kABPersonFirstNameProperty, line, &error);
} else if ([line hasPrefix:#"Middle Name: "]) {
[mutableLine deleteCharactersInRange: [mutableLine rangeOfString: #"Middle Name: "]];
line = (NSString *)mutableLine;
ABRecordSetValue(person, kABPersonMiddleNameProperty, line, &error);
} else if ([line hasPrefix:#"Last Name: "]) {
[mutableLine deleteCharactersInRange: [mutableLine rangeOfString: #"Last Name: "]];
line = (NSString *)mutableLine;
ABRecordSetValue(person, kABPersonLastNameProperty, line, &error);
} else if ([line rangeOfString: #"Phone:"].location!=NSNotFound) {
NSString *phoneLabel = [[line componentsSeparatedByString:#" Phone: "] objectAtIndex:0];
NSString *phoneContent = [[line componentsSeparatedByString:#" Phone: "] objectAtIndex:1];
if ([phoneLabel isEqualToString:#"Mobile"]) {
ABMultiValueAddValueAndLabel(multiPhone, phoneContent, kABPersonPhoneMobileLabel, NULL);
ABRecordSetValue(person, kABPersonPhoneProperty, multiPhone, &error);
} else if ([phoneLabel isEqualToString:#"Home"]) {
ABMultiValueAddValueAndLabel(multiPhone, phoneContent, kABHomeLabel, NULL);
ABRecordSetValue(person, kABPersonPhoneProperty, multiPhone, &error);
} else if ([phoneLabel isEqualToString:#"Work"]) {
ABMultiValueAddValueAndLabel(multiPhone, phoneContent, kABWorkLabel, NULL);
ABRecordSetValue(person, kABPersonPhoneProperty, multiPhone, &error);
} else if ([phoneLabel isEqualToString:#"iPhone"]) {
ABMultiValueAddValueAndLabel(multiPhone, phoneContent, kABPersonPhoneIPhoneLabel, NULL);
ABRecordSetValue(person, kABPersonPhoneProperty, multiPhone, &error);
} else {
ABMultiValueAddValueAndLabel(multiPhone, phoneContent, (CFStringRef)phoneLabel, NULL);
ABRecordSetValue(person, kABPersonPhoneProperty, multiPhone, &error);
}
}else if ([line rangeOfString: #"Email:"].location!=NSNotFound) {
NSString *emailLabel = [[line componentsSeparatedByString:#" Email: "] objectAtIndex:0];
NSString *emailContent = [[line componentsSeparatedByString:#" Email: "] objectAtIndex:1];
if ([emailLabel isEqualToString:#"Main"]) {
ABMultiValueAddValueAndLabel(multiEmail, emailContent, (CFStringRef)#"Main", NULL);
ABRecordSetValue(person, kABPersonEmailProperty, multiEmail, &error);
}else if ([emailLabel isEqualToString:#"Work"]) {
ABMultiValueAddValueAndLabel(multiEmail, emailContent, kABWorkLabel, NULL);
ABRecordSetValue(person, kABPersonEmailProperty, multiEmail, &error);
} else {
ABMultiValueAddValueAndLabel(multiEmail, emailContent, (CFStringRef)emailLabel, NULL);
ABRecordSetValue(person, kABPersonEmailProperty, multiEmail, &error);
}
}
if ([line hasPrefix:#"- -"]) {
//ABRecordSetValue(person, kABPersonEmailProperty, multiEmail, &error);
NSString *updateText;
NSString *firstName = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString *lastName = (NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
if (![self personAlreadyExists:firstName withName:lastName]){
ABAddressBookAddRecord(addressBook, person, &error);
ABAddressBookSave(addressBook, &error);
recordNumber++;
if (firstName==nil) {
updateText = [NSString stringWithFormat:#"%# added.", lastName];
} else if (lastName==nil) {
updateText = [NSString stringWithFormat:#"%# added.", firstName];
} else {
updateText = [NSString stringWithFormat:#"%# %# added.", firstName, lastName];
}
//NSLog(updateText);
} else {
if (firstName==nil) {
updateText = [NSString stringWithFormat:#"%# skipped.", lastName];
} else if (lastName==nil) {
updateText = [NSString stringWithFormat:#"%# skipped.", firstName];
} else {
updateText = [NSString stringWithFormat:#"%# %# skipped.", firstName, lastName];
}
//NSLog(updateText);
}
updateLabel.text = [updateLabel.text stringByAppendingFormat:#"%#\n", updateText];
statusLabel.text = #"";
NSLog(#"%i/%i Imported", recordNumber, totalRecords);
}
if (error != NULL) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Could not create contact" delegate:nil cancelButtonTitle:#"Cancel" otherButtonTitles:nil];
[alert show];
[alert release];
}
}
}
//[importLines release];
[activity stopAnimating];
activity.hidden = TRUE;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Add To Contacts" message:[NSString stringWithFormat:#"Contacts successfully restored!", ABRecordCopyValue(person, kABPersonFirstNameProperty)] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
Some of our app store users are reporting a crash while searching their address book.
I'm pretty lost here cause I can't reproduce this issue.
Is there anything wrong with how I'm querying the address book ? Thanks!!
+ (NSDictionary *) scanAddressBook
{
#if TARGET_OS_IPHONE
NSUInteger i;
CFIndex index;
ABAddressBookRef addressBook = ABAddressBookCreate();
NSArray *people = (NSArray *) ABAddressBookCopyArrayOfAllPeople(addressBook);
if ( people==nil || (people && ([people count] == 0)))
{
TRACE_LOG(#"scanAddressBook ", #"NO ADDRESS BOOK ENTRIES TO SCAN");
if(people) [people release];
CFRelease(addressBook);
return nil;
}
NSMutableArray *numbersArray = [NSMutableArray new];
NSMutableArray *mailsArray = [NSMutableArray new];
for ( i=0; i<[people count]; i++ )
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
ABRecordRef person = (ABRecordRef)[people objectAtIndex:i];
NSMutableDictionary *phoneDictionary = [NSMutableDictionary new];
CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
CFStringRef lastName = ABRecordCopyValue(person, kABPersonLastNameProperty);
NSString* log =[NSString stringWithFormat:#"-----CONTACT ENTRY -> %# : %#", firstName, lastName ];
TRACE_LOG(#"scanAddressBook",log);
NSString *userName = #"NoName";
if (firstName && lastName)
userName = [NSString stringWithFormat:#"%# %#", firstName, lastName];
else if (firstName)
userName = [NSString stringWithFormat:#"%#", firstName];
else if (lastName)
userName = [NSString stringWithFormat:#"%#", lastName];
if(firstName) CFRelease(firstName);
if(lastName) CFRelease(lastName);
//
// Phone Numbers
//
ABMutableMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);
CFIndex phoneNumberCount = ABMultiValueGetCount( phoneNumbers );
for ( index=0; index<phoneNumberCount; index++ )
{
CFStringRef phoneNumberLabel = ABMultiValueCopyLabelAtIndex( phoneNumbers, index);
CFStringRef phoneNumberValue = ABMultiValueCopyValueAtIndex( phoneNumbers, index);
CFStringRef phoneNumberLocalizedLabel = ABAddressBookCopyLocalizedLabel( phoneNumberLabel );
// converts "_$!<Work>!$_" to "work" and "_$!<Mobile>!$_" to "mobile"
// Find the ones you want here
//
NSString* log =[NSString stringWithFormat:#"-----PHONE ENTRY -> %# : %#", phoneNumberLocalizedLabel, phoneNumberValue ];
TRACE_LOG(#"scanAddressBook",log);
if (![NetworkingUtils validatePhoneNumber:(NSString *)phoneNumberValue]) {
NSLog(#"invalid phone number: %#",phoneNumberValue);
CFRelease(phoneNumberLocalizedLabel);
CFRelease(phoneNumberLabel);
CFRelease(phoneNumberValue);
continue;
}
[phoneDictionary setObject:(NSString *)phoneNumberValue forKey:InviteUserDataNumberKeyID];
[phoneDictionary setObject:(NSString *)phoneNumberLocalizedLabel forKey:InviteUserDataNumberTypeKeyID];
[phoneDictionary setObject:(NSString *)userName forKey:InviteUserDataNameTypeKeyID];
CFRelease(phoneNumberLocalizedLabel);
CFRelease(phoneNumberLabel);
CFRelease(phoneNumberValue);
NSMutableDictionary *copyPhoneDict = [phoneDictionary copy];
[numbersArray addObject:copyPhoneDict];
[copyPhoneDict release];
}
CFRelease(phoneNumbers);
[phoneDictionary release];
NSMutableDictionary *mailDictionary = [NSMutableDictionary new];
ABMutableMultiValueRef emails = ABRecordCopyValue(person, kABPersonEmailProperty);
CFIndex mailsNumberCount = ABMultiValueGetCount( emails );
for ( index=0; index < mailsNumberCount; index++ )
{
CFStringRef emailValue = ABMultiValueCopyValueAtIndex( emails,index);
// converts "_$!<Work>!$_" to "work" and "_$!<Mobile>!$_" to "mobile"
// Find the ones you want here
//
NSString* log =[NSString stringWithFormat:#"-----EMAIL ENTRY -> : %#", emailValue ];
TRACE_LOG(#"scanAddressBook",log);
if (![NetworkingUtils validateEmail:(NSString *)emailValue]) {
NSLog(#"invalid email address: %#",(NSString *)emailValue);
if (emailValue) {
CFRelease(emailValue);
}
continue;
}
[mailDictionary setObject:(NSString *)emailValue forKey:InviteUserDataMailKeyID];
[mailDictionary setObject:(NSString *)#"email" forKey:InviteUserDataMailTypeKeyID];
[mailDictionary setObject:(NSString *)userName forKey:InviteUserDataMailOwnerKeyID];
if (emailValue) {
CFRelease(emailValue);
}
NSMutableDictionary *copyMailDict = [mailDictionary copy];
[mailsArray addObject:copyMailDict];
[copyMailDict release];
}
if(emails) CFRelease(emails);
[mailDictionary release];
[pool drain];
}
NSString *countryCode = [[NSUserDefaults standardUserDefaults] objectForKey:RequestUserCountryCodeKeyID];
if (!countryCode) {
NSLocale *locale = [NSLocale currentLocale];
NSString *aCode = [locale objectForKey: NSLocaleCountryCode];
countryCode = [[NetworkingUtils codesByCountryCode] objectForKey:aCode];
}
NSDictionary *aDictionary = [NSDictionary dictionaryWithObjectsAndKeys: [[numbersArray copy] autorelease], InviteUsersNumbersArrayKeyID,
[[mailsArray copy] autorelease], InviteUsersMailsArrayKeyID,
countryCode, RequestUserCountryCodeKeyID, nil];
[numbersArray release];
[mailsArray release];
[people release];
CFRelease(addressBook);
return aDictionary;
#else
return nil ;
#endif
}
CFRelease() will crash if you provide a NULL value. I see most of your CFRelease() calls do check for NULL, but not all of them.
Most likely one of these is triggering the crash?
I'm not very familiar with ABAddressBook, so don't know in what situations they would return NULL.
On a related note, Objective-C's -release method does not crash on nil, so you may as well change: if(people) [people release]; to just [people release]; as all methods in Objective-C will silently do nothing if sent to a nil.
this is my code and it works flawless, where my_value is a string with separator ','.
everythign works fin but i'd like to display the person record from the address book after i saved it, so in the function
if(isSaved) {
// **** code here ***
}
here the complete function
- (void) addToAgenda: (NSString*) my_value{
//NSArray *strings = [my_value componentsSeparatedByString: #","];
NSArray *dati=[[NSArray alloc] initWithArray:[my_value componentsSeparatedByString:#","]];
NSString *userwebsite = [dati objectAtIndex:0];
NSString *fname = [dati objectAtIndex:1];
NSString *lname = [dati objectAtIndex:2];
NSString *useremail = [dati objectAtIndex:3];;
NSString *usermobile = [dati objectAtIndex:4];
NSString *usercompany = #"xxx";
ABRecordRef aRecord = ABPersonCreate();
CFErrorRef anError = NULL;
// fisrst name
ABRecordSetValue(aRecord, kABPersonFirstNameProperty, fname, &anError);
// last name
ABRecordSetValue(aRecord, kABPersonLastNameProperty, lname, &anError);
// Phone Number.
ABMutableMultiValueRef multi = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMultiValueAddValueAndLabel(multi, (CFStringRef)usermobile, kABWorkLabel, NULL);
ABRecordSetValue(aRecord, kABPersonPhoneProperty, multi, &anError);
CFRelease(multi);
// Company
ABRecordSetValue(aRecord, kABPersonDepartmentProperty, usercompany, &anError);
// email
NSLog(#"%#", useremail);
ABMutableMultiValueRef multiemail = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMultiValueAddValueAndLabel(multiemail, (CFStringRef)useremail, kABWorkLabel, NULL);
ABRecordSetValue(aRecord, kABPersonEmailProperty, multiemail, &anError);
CFRelease(multiemail);
// website
NSLog(#"%#", userwebsite);
ABMutableMultiValueRef multiweb = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMultiValueAddValueAndLabel(multiweb, (CFStringRef)userwebsite, kABWorkLabel, NULL);
ABRecordSetValue(aRecord, kABPersonURLProperty, multiweb, &anError);
CFRelease(multiemail);
if (anError != NULL)
NSLog(#"error while creating..");
CFStringRef personname, personlname, personcompind, personemail, personwebsite, personcontact;
personname = ABRecordCopyValue(aRecord, kABPersonFirstNameProperty);
personlname = ABRecordCopyValue(aRecord, kABPersonLastNameProperty);
personcompind = ABRecordCopyValue(aRecord, kABPersonDepartmentProperty);
personemail = ABRecordCopyValue(aRecord, kABPersonEmailProperty);
personwebsite = ABRecordCopyValue(aRecord, kABPersonURLProperty);
personcontact = ABRecordCopyValue(aRecord, kABPersonPhoneProperty);
ABAddressBookRef addressBook;
CFErrorRef error = NULL;
addressBook = ABAddressBookCreate();
BOOL isAdded = ABAddressBookAddRecord (addressBook, aRecord, &error);
if(isAdded){
NSLog(#"added..");
}
if (error != NULL) {
NSLog(#"ABAddressBookAddRecord %#", error);
}
error = NULL;
BOOL isSaved = ABAddressBookSave (addressBook, &error);
if(isSaved) {
// **** code here ***
}
if (error != NULL) {
NSLog(#"ABAddressBookSave %#", error);
UIAlertView *alertOnChoose = [[UIAlertView alloc] initWithTitle:#"Unable to save this time" message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok", nil];
[alertOnChoose show];
[alertOnChoose release];
}
CFRelease(aRecord);
CFRelease(personname);
CFRelease(personlname);
CFRelease(personcompind);
CFRelease(personcontact);
CFRelease(personemail);
CFRelease(personwebsite);
CFRelease(addressBook);
}
You can use something like ABPersonViewController to display aRecord. Since it is a subclass of UIViewController, you can show it just like any other view controller, such as pushing it onto your navigation controller stack or presenting it modally.