how to edit a phone number values programmatically from address book ios - iphone

I'm trying to replace an specific phone number for an specific contact programmatically in iOS, taking the contacts form address book.
I don't know why I can't save the new phone number and refresh the address book to show the change.
I'm doing this:
+(BOOL) changeContactPhoneNumber:(NSString *) phoneSought
forThis:(NSString *) newPhoneNumber{
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef contactSelected;
CFStringRef mobileLabelNumber;
CFErrorRef error = nil;
// Do whatever you want here.
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
for (int i = 0; i < nPeople; i++)
{
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i);
ABMultiValueRef phones = (ABMultiValueRef)ABRecordCopyValue(ref, kABPersonPhoneProperty);
NSString* mobilePhoneNumber=#"";
if (ABMultiValueGetCount(phones) > 0) {
for (int i=0; i < ABMultiValueGetCount(phones); i++) {
[mobilePhoneNumber release];
mobilePhoneNumber = (NSString*)ABMultiValueCopyValueAtIndex(phones, i);
if([mobilePhoneNumber isEqualToString:phoneSought]){
contactSelected = ref;
mobileLabelNumber = ABMultiValueCopyLabelAtIndex(phones, i);
}
}
}
}
ABMutableMultiValueRef phoneNumberMultiValue = ABMultiValueCreateMutable(kABPersonPhoneProperty);
bool didAddPhone = ABMultiValueAddValueAndLabel(phoneNumberMultiValue ,(__bridge CFTypeRef)newPhoneNumber,mobileLabelNumber, NULL);
if(didAddPhone){
ABRecordSetValue(ABAddressBookGetPersonWithRecordID(addressBook, contactSelected),
kABPersonPhoneProperty,
phoneNumberMultiValue,
nil);
bool bSuccess = ABAddressBookSave(addressBook, &error);
if (!bSuccess) {
NSLog(#"Could not save to address book: %#", error);
} else {
return YES;
}
} else {
NSLog(#"Error editing phone number: %#", error);
error = nil;
}
return NO;
}

You should debug your code and try to figure out whether the format of the phone numbers you are providing to the method are matching or not.
For e.g. when i am logging my contact list phone numbers these are results
Number...555-478-7672
Number...(408) 439-5270
Number...(408) 555-3514
Number...888-555-5512
Number...888-555-1212
Number...555-522-8243
Number...(555) 766-4823
Number...(707) 555-1854
Number...555-610-6679
And i was comparing these number against unformatted number string.
Secondly
ABRecordSetValue(ABAddressBookGetPersonWithRecordID(addressBook, contactSelected),
kABPersonPhoneProperty,
phoneNumberMultiValue,
nil);
Whose actual declaration is
ABRecordSetValue(ABRecordRef record, ABPropertyID property, CFTypeRef value, CFErrorRef* error);
Although ABAddressBookGetPersonWithRecordID returns a ABRecordRef but you already have ABRecordRef contactSelected; so in my view you should use
ABRecordSetValue(contactSelected,kABPersonPhoneProperty,phoneNumberMultiValue,nil);
Please correct me if i am wrong or have misunderstood your code!

Related

IOS: AddressBook Ui Framework

I want to select multiple contacts from an address book and i want to store the images of the selected persons in an mutable array. I have searched through the internet completely but i cant get any samples. Any one please help
Thanks in advance
First You have to add the
"AddressBook.framework" framework and add header file :
import.
// this method
#pragma mark- find all contacts email id
-(void)getFilterEmailid{
NSUInteger i;
NSUInteger k;
ABAddressBookRef addressBook = ABAddressBookCreate();
NSArray *people = (NSArray *) ABAddressBookCopyArrayOfAllPeople(addressBook);
if ( people==nil )
{
NSLog(#"NO ADDRESS BOOK ENTRIES TO SCAN");
CFRelease(addressBook);
return;
}
for ( i=0; i<[people count]; i++ )
{
ABRecordRef person = (ABRecordRef)[people objectAtIndex:i];
NSString *home=#"";
NSString *work=#"";
//
// Phone Numbers
//
ABMutableMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonEmailProperty);
CFIndex phoneNumberCount = ABMultiValueGetCount( phoneNumbers );
// Here we can get the Image ref
CFDataRef imageData = ABPersonCopyImageData(person);
// This is the Image Data you can use as you want to.
NSData *data = (NSData *)imageData;
for ( k=0; k<phoneNumberCount; k++ )
{
CFStringRef phoneNumberLabel = ABMultiValueCopyLabelAtIndex( phoneNumbers, k );
CFStringRef phoneNumberValue = ABMultiValueCopyValueAtIndex( phoneNumbers, k );
CFStringRef phoneNumberLocalizedLabel = ABAddressBookCopyLocalizedLabel( phoneNumberLabel ); // converts "_$!<Work>!$_" to "work" and "_$!<Mobile>!$_" to "mobile"
// Find the ones you want here
//
NSLog(#"-----PHONE ENTRY -> %# : %#", phoneNumberLocalizedLabel, phoneNumberValue );
home=[(NSString*)phoneNumberLocalizedLabel copy ];
work=[(NSString *)phoneNumberValue copy];
NSLog(#"home=%# work=%#",home,work);
CFRelease(phoneNumberLocalizedLabel);
CFRelease(phoneNumberLabel);
CFRelease(phoneNumberValue);
// This is my array i save only the Email id. You can save what value you want
[emailIdArray addObject:work];
}
}
[people release];
CFRelease(addressBook);
}

Copying contacts from one source to another

I'm trying to copy contacts between my Local contact source and the iCloud contact source and I'm not seeing any results. This code executes without error and seems like it should work, but I don't see the newly created contacts afterward. Anyone see any issues with it?
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef abSourceSource = ABAddressBookGetSourceWithRecordID(addressBook, kABSourceTypeLocal);
ABRecordRef abDestinationSource = ABAddressBookGetSourceWithRecordID(addressBook, kABSourceTypeCardDAV);
CFArrayRef sourceContacts = ABAddressBookCopyArrayOfAllPeopleInSource(addressBook, abSourceSource);
CFArrayRef destinationContacts = ABAddressBookCopyArrayOfAllPeopleInSource(addressBook, abDestinationSource);
ABPersonCreatePeopleInSourceWithVCardRepresentation(abDestinationSource, ABPersonCreateVCardRepresentationWithPeople(sourceContacts));
ABPersonCreatePeopleInSourceWithVCardRepresentation(abSourceSource, ABPersonCreateVCardRepresentationWithPeople(destinationContacts)));
ABAddressBookSave(addressBook, NULL);
There is a more fundamental problem - you are not calling ABAddressBookGetSourceWithRecordID properly. The 2nd parameter it takes is an int that specifies the record id of a particular source in your address book. You are passing it a constant that describes the type of a particular source.
The constant you are passing, kABSourceTypeCardDav is always 4. However, the record id of the iCloud source in a user's address book can be something very different.
What you need to do is enumerate all the sources and test their types, like so:
NSArray *allSources = (NSArray*)ABAddressBookCopyArrayOfAllSources(addressBook);
for (int i = 0; i < allSources.count; i++) {
ABRecordRef src = [allSources objectAtIndex:i];
NSNumber *stObj = (NSNumber*)ABRecordCopyValue(src, kABSourceTypeProperty);
ABSourceType st = (ABSourceType)[stObj intValue];
if (st == kABSourceTypeCardDAV) {
int recordID = ABRecordGetRecordID(src);
break;
}
}
Then you could use recordID as the argument to the first function
I think you forgot to add the records with ABAddressBookAddRecord. Here is my working example:
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef abSource = ABAddressBookGetSourceWithRecordID(addressBook, kABSourceTypeLocal);
NSURL *theURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"some.vcf"];
NSData *vCardData = [NSData dataWithContentsOfURL:theURL];
NSLog(#"data %#", vCardData);
NSArray *createdPeople = (__bridge_transfer NSArray*)ABPersonCreatePeopleInSourceWithVCardRepresentation(abSource, (__bridge CFDataRef)vCardData);
NSLog(#"createdPeople %#", createdPeople);
CFErrorRef error = NULL;
bool ok;
for (id person in createdPeople) {
error = NULL;
ok = ABAddressBookAddRecord(addressBook, (__bridge ABRecordRef)person, &error);
if (!ok) {
NSLog(#"add err %#", error);
break;
}
}
if (ok) {
error = NULL;
BOOL isSaved = ABAddressBookSave(addressBook, &error);
if (isSaved) {
NSLog(#"saved..");
}
if (error != NULL) {
NSLog(#"ABAddressBookSave %#", error);
}
}
CFRelease(addressBook);

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

Why I'm getting “EXC_BAD_ACCESS” upon trying to release?

Would you please have a look at me code:
(void)loadContactsFromAddressBook {
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex count = ABAddressBookGetPersonCount(addressBook);
ABRecordRef person;
for (int i = 0; i < count; i++) {
person = CFArrayGetValueAtIndex(allPeople, i);
CFStringRef cfStr = ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString* firstName = (NSString*) cfStr;
[contacts addObject:firstName];
CFRelease(cfStr);
}
CFRelease(addressBook);
CFRelease(allPeople);
}
I tried to CFRelease(person) after the for block but the application crashes with “EXC_BAD_ACCESS”. If I remove CFRelease(person), the application works.
You didn't create the person, you only referenced it. Insert child support joke here.

Retrieving instant message information from an ABRecordRef

I'm trying to get the instant message account information from existing AddressBook contacts on iOS. I walk through the contacts and I get the contacts which have an instant messaging value, but I can't read the jabber-address.
abArray = (NSArray *)ABAddressBookCopyArrayOfAllPeople(ABAddressBookCreate());
for(int i=0 ; i<[abArray count];i++)
{
ABRecordRef record = [abArray objectAtIndex:i];
ABMutableMultiValueRef multi = ABRecordCopyValue(record, kABPersonInstantMessageProperty);
for(CFIndex x=0;x<ABMultiValueGetCount(multi);x++)
{
CFDictionaryRef dict = ABMultiValueCopyValueAtIndex(multi, x);
CFStringRef jabber = CFDictionaryGetValue(dict, kABPersonInstantMessageServiceJabber);
if(CFDictionaryContainsKey(dict, kABPersonInstantMessageServiceJabber))
{
NSLog(#"yes");
}
else {
NSLog(#"no");
}
// only to make it possible to log to console
NSString *jaab = (NSString *)jabber;
NSLog(#"jabber adress: %#" , jaab);
}
CFRelease(dict);
}
}
What am I doing wrong?
for(int i=0 ; i<[abArray count];i++)
{
ABRecordRef record = [abArray objectAtIndex:i];
ABMutableMultiValueRef multi = ABRecordCopyValue(record, kABPersonInstantMessageProperty);
for(CFIndex x=0;x<ABMultiValueGetCount(multi);x++)
{
CFDictionaryRef dict = ABMultiValueCopyValueAtIndex(multi, x);
CFStringRef jabber;
//Use this piece of code to print the dict to log and check
NSDictionary *nsdict = (NSDictionary *)dict;
NSString *jabberID = [NSString stringWithString:#""];
NSLog(#"Dict: %#", nsdict);
if([[nsdict valueForKey:#"service"] isEqualToString:#"Jabber"]){
jabberID = [nsdict valueForKey:#"username"];
}
//Code to print dict to log ends here. Comment the whole piece if not needed.
if(CFStringCompare((CFStringRef)#"jabber", CFDictionaryGetValue(dict, #"service"), 0))
{
NSLog(#"yes");
jabber = CFDictionaryGetValue(dict, #"username");
// only to make it possible to log to console
NSString *jaab = (NSString *)jabber;
NSLog(#"jabber adress: %#" , jaab);
}
else {
NSLog(#"no");
}
}
//CFRelease(dict);
}