App crashes when fetching record from address book - iphone

I need to fetch record from address book. I'm using ABPeoplePickerNavigationController to do so. While fetching record I'm putting a check condition to check record exist or not.
For example to check there is first name I'm using the following code
NSString *fname;
CFTypeRef fnameProperty = ABRecordCopyValue(person, kABPersonFirstNameProperty);
if (ABRecordCopyValue(person, kABPersonFirstNameProperty)) {
fname = (__bridge NSString*)fnameProperty;
}
else{
fname = #"";
}
The code works perfectly for kABPersonFirstNameProperty.
But when I'm using following piece of code to check email property
ABMultiValueRef emailProperty = ABRecordCopyValue(person, kABPersonEmailProperty);
NSLog(#"%#",emailProperty);
NSString *email;
if (ABRecordCopyValue(person, kABPersonEmailProperty)) {
email = (__bridge NSString*)ABMultiValueCopyValueAtIndex(emailProperty, 0);
}
else {
email = #"";
}
My app crashes if kABPersonEmailProperty is nil(there is no email property stored for the person)
Can somebody explain me why is this happening?
Thanks

Here's is my working version, see if this works.
//Email
NSString* email = nil;
ABMultiValueRef emailNum = ABRecordCopyValue(person,
kABPersonEmailProperty);
if (ABMultiValueGetCount(emailNum) > 0) {
email = (__bridge_transfer NSString*)
ABMultiValueCopyValueAtIndex(emailNum, 0);
} else {
email = #"";
}

Related

Extracting contact variables from profile page (phone #, email address, photo) to iOS Phonebook Contact List

I'd like to load information from user profiles in my app, into the iPhone Phonebook/Contact List.
My app has user profiles that contain various attributes about the person in which they're representing, such as their phone number, name, school, education level, email address, photo, summary of what they do, their interests etc.
What I'd like to be able to do, is for another user to be able to extract (with one click) contact attributes from this profile page so that it gets imported into the iPhone Contact List.
So for example, if I liked UserA, and I wanted to add her to my iPhone contact list, I would be able to click "Add to Contacts" which would then import all of UserA's relevant profile information (phone #, email address, street address, URL, photo, etc.) and create UserA as a new contact in my iPhone Phonebook.
Is this possible using iphone's abpeoplepicker api? If so, how do I go about executing this (where can I reference proper documentation), and what are the limitations/contraints/criteria in which this can be possible?
framework:
#import "AddressBook/AddressBook.h"
Code:
- (void) getLocalContacts
{
ABAddressBookRef addressBook = ABAddressBookCreate( );
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook );
CFIndex nPeople = ABAddressBookGetPersonCount( addressBook );
User *user;
NSMutableArray *allContacts = [[NSMutableArray alloc] init];
for ( int i = 0; i < nPeople; i++ )
{
ABRecordRef person = CFArrayGetValueAtIndex( allPeople, i );
ABMultiValueRef emails = ABRecordCopyValue(person, kABPersonEmailProperty);
if(ABMultiValueGetCount(emails) != 0)
{
user = [[User alloc] init];
CFStringRef fName, lName;
fName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
lName = ABRecordCopyValue(person, kABPersonLastNameProperty);
CFStringRef email = ABMultiValueCopyValueAtIndex(emails, 0);
NSData *imgData = (NSData *)ABPersonCopyImageData(person);
NSString *firstName = (NSString *) fName;
NSString *lastName = (NSString *) lName;
if (firstName.length == 0 && lastName.length != 0){
user.userName = lastName;
}
else if (firstName.length != 0 && lastName.length == 0){
user.userName = firstName;
}
else if (firstName.length == 0 && lastName.length == 0){
user.userName = #"";
}
else if (firstName.length != 0 && lastName.length != 0){
user.userName = [NSString stringWithFormat:#"%# %#", firstName, lastName];
}
//user.firstName = (NSString *) firstName;
user.lastName = #"";
user.email = (NSString *) email;
user.firstName = (NSString *) email;
user.localImage = [UIImage imageWithData:imgData];
[allContacts addObject:user];
[user release];
}
}
[DataManager sharedManager].allLocalUsers = allContacts;
[self hideSpinner];
}

How to access contacts only with email address in address book?

I am accessing all of the users contacts and emailing them through the app. I can access all of the contacts fine, if they have an email address. If they don't have an email address, then it gives me an error, I am trying to check if they have an email address before I attempt to add the address to the list of addresses. I am using this code. It gives me an error on the line of the if statement here: if ((ABMultiValueCopyValueAtIndex(email, 0) != NULL))
How can I access only the contacts who have email addresses?
NSMutableArray* contactsArray = [NSMutableArray new];
ABAddressBookRef m_addressbook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(m_addressbook);
CFIndex nPeople = ABAddressBookGetPersonCount(m_addressbook);
for (int i=0;i < nPeople;i++)
{
NSMutableDictionary* tempContactDic = [NSMutableDictionary new];
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople,i);
CFStringRef firstName, lastName;
firstName = ABRecordCopyValue(ref, kABPersonFirstNameProperty);
lastName = ABRecordCopyValue(ref, kABPersonLastNameProperty);
NSString *name = [NSString stringWithFormat:#"%# %#", firstName, lastName];
[tempContactDic setValue:name forKey:#"name"];
//fetch email id
NSString *strEmail;
ABMultiValueRef email = ABRecordCopyValue(ref, kABPersonEmailProperty);
if ((ABMultiValueCopyValueAtIndex(email, 0) != NULL))
{
CFStringRef tempEmailref = ABMultiValueCopyValueAtIndex(email, 0);
strEmail = (__bridge NSString *)tempEmailref;
[contactsArray addObject:strEmail];
}
}
The error is because you are trying to check whether there are email address available by copying the first item in the array and check if the value is NULL. But if the array is empty you can't copy any items from it.
What you should do is check if the array holds any items:
if (ABMultiValueGetCount(email) > 0) {
// There is at least one item in the email array/
}
Also be aware they your code only copies the first e-mail address for the contact, if more then 1 e-mail is set for that contact you might want to loop thru the e-mail array.
U can use this code to fetch all emails of all users from your contacts.
- (void) getEmailsOfAllContacts
{
ABAddressBookRef _addressBookRef = ABAddressBookCreate();
NSArray * allPeople = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(_addressBookRef);
for (id record in allPeople)
{
CFTypeRef emailProperty = ABRecordCopyValue((__bridge ABRecordRef)record, kABPersonEmailProperty);
NSArray * allEmailArray = ((__bridge NSArray *)ABMultiValueCopyArrayOfAllValues(emailProperty));
NSString * email;
for (int i = 0; i < [allEmailArray count]; i++)
{
email = [allEmailArray objectAtIndex: i];
if (isEmpty(email) == NO)
{
[_allContactsEmailArray addObject: email];
}
}
}
CFRelease(_addressBookRef);
allPeople = nil;
}

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

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

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