Is this the right way to delete a contact from the iPhone? - iphone

I am trying to delete a contact from the iPhone which I have created. I tried to find a good working example of deleting a contact, however didn't find one. Adding a contact seemed quite easy but deleting one seems hard. The following code does not work, but it seemed to be plausible:
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef delete = ABPersonCreate();
ABRecordSetValue(delete, kABPersonFirstNameProperty, #"Max", nil);
ABRecordSetValue(delete, kABPersonLastNameProperty, #"Mustermann", nil);
ABAddressBookRemoveRecord(addressBook, delete, &error);
ABAddressBookSave(addressBook, &error);
Could anyone help me out.
Thanks in advance for your help.
Max

The problem is that you're creating an ABRecord that isn't inside of the address book. What you have to do is search through an array of ABRedords from the ABAddressBook. I wrote how to do this for you:
CFErrorRef error = nil;
ABAddressBookRef addressBook = ABAddressBookCreate();
__block ABRecordRef toDelete = ABPersonCreate();
ABRecordSetValue(toDelete, kABPersonFirstNameProperty, #"Max", nil);
ABRecordSetValue(toDelete, kABPersonLastNameProperty, #"Mustermann", nil);
// Gets the array of everybody in the address book
NSArray *peopleArray = (__bridge NSArray *) ABAddressBookCopyArrayOfAllPeople(addressBook);
// Creates a test predicate to see if the ABRecord has the same name as toDelete
BOOL (^predicate)(id obj, NSUInteger idx, BOOL *stop) = ^(id obj, NSUInteger idx, BOOL *stop) {
ABRecordRef person = (__bridge ABRecordRef)obj;
CFComparisonResult result = ABPersonComparePeopleByName(person, delete, kABPersonSortByLastName);
bool pass = (result == kCFCompareEqualTo);
if (pass) {
toDelete = person;
}
return (BOOL) pass;
};
int idx = [peopleArray indexOfObjectPassingTest:predicate];
bool removed = ABAddressBookRemoveRecord(addressBook, toDelete, &error);
bool saved = ABAddressBookSave(addressBook, &error);
You can change how you want to compare ABRecord instances by changing the block code. All it's doing now is comparing the names of the contacts.
A caveat with this code is that it will only delete one instance of the ABRecords whose name matches delete’s.

Related

how to add a contacts to a particular group ? ios

Fetching contacts and creating group and pushing the contact inot group using group id is getting failed in ios
i check the Group exists already or not and create group if no available
-(void) CheckIfGroupExistWithName:(NSString*)groupName {
BOOL hasGroup = NO;
//checks to see if the group is created ad creats group for contacts
// ABAddressBookRef addressBook = ABAddressBookCreate();
CFIndex groupCount = ABAddressBookGetGroupCount(addressBook);
CFArrayRef groupLists= ABAddressBookCopyArrayOfAllGroups(addressBook);
for (int i=0; i<groupCount; i++) {
ABRecordRef currentCheckedGroup = CFArrayGetValueAtIndex(groupLists, i);
NSString *currentGroupName = (__bridge NSString *)ABRecordCopyCompositeName(currentCheckedGroup);
NSLog(#"GroupName= %#",groupName);
if ([currentGroupName isEqualToString:groupName]){
//!!! important - save groupID for later use
groupId = ABRecordGetRecordID(currentCheckedGroup);
NSLog(#"group id = %i",groupId);
hasGroup=YES;
}
}
if (hasGroup==NO){
//id the group does not exist you can create one
[self createNewGroup:groupName];
}
//CFRelease(currentCheckedGroup);
CFRelease(groupLists);
//CFRelease(addressBook);
}
get the contact details and tries to save by this way
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person
{
NSString *name = (__bridge NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
contactNameText.text=name;
ABMultiValueRef phones = (ABMultiValueRef)ABRecordCopyValue(person, kABPersonPhoneProperty);
NSString* mobile=#"";
mobile = (__bridge NSString*)ABMultiValueCopyValueAtIndex(phones, 0);
contactNoText.text=mobile;
CFErrorRef error=NULL;
addressBook = ABAddressBookCreate();
ABRecordRef ICEBUZZGroup = ABAddressBookGetGroupWithRecordID(addressBook, groupId);
BOOL didAdd = ABGroupAddMember(ICEBUZZGroup,person,&error);
if (!didAdd) {
}
BOOL didSave = ABAddressBookSave(addressBook, &error);
if (!didSave) {
}
PLs help
Thank in advance

how to get records of contacts from NSMutableArray in iPhone

I have an array of dictionary for contact details. I am trying to add that record in ABRecordRef, but I don't understand how it works. Here is my code:
for (int i = 0; i <= [contactArray count]; i++)
{
ABRecordRef person = (ABRecordRef)[contactArray objectAtIndex:i];
ABAddressBookAddRecord(addressBook, group, &error);
ABAddressBookSave(addressBook, &error);
}
I am trying to add this contact records into group using ABGroupAddMember. Now how can I get the records from NSMutableArray. Any help will be greatly appreciated. Thank you.
there is no built-in functionality for that. you will have to create an empty record, THEN get all the fields from the dict and THEN add those to the record and safe it
that's annoying manual work... :D
I'd go with Erica's ABContactHelper: https://github.com/erica/ABContactHelper
then it is only
for(NSDictionary *d in recordArray) {
ABContact *contact = [ABContact contactWithDictionary:d];
ABGroupAddMember(theGroup, contact.record);
}
if you like manual:
for(NSDictionary *d in recordArray) {
ABRecordRef person = ABPersonCreate();
for(NSString *k in d.allKeys) {
id v = d[k];
//HERE call ABRecordSetValue with the right params depending on if the value is a NSString or NSArray or an image
}
ABGroupAddMember(theGroup, contact.record);
CFRelease(person);
}
disclaimer: typed inline but should be ok

How to edit email & phone number values programmatically from addressbook in iOS 5 +

I want to email & phone number values programmatically from addressbook in iOS 5 +. I tried following code. It changes the first name & last name but not the email & phone number.
Here is my code
ABAddressBookRef addressBook=ABAddressBookCreate();
ABRecordRef record = ABAddressBookGetPersonWithRecordID(addressBook, [userInfo.userId intValue]);
NSNumber *recordId = [NSNumber numberWithInteger:ABRecordGetRecordID(record)];
NSLog(#"recordId:- %d",[recordId intValue]);
// First & Last name
ABRecordSetValue(record, kABPersonFirstNameProperty, (__bridge void*)userInfo.firstName , nil);
ABRecordSetValue(record, kABPersonLastNameProperty, (__bridge void*)userInfo.lastName, nil);
//Phone number is a list , so create a multivalue
ABMutableMultiValueRef phoneNumberMultiValue =
ABMultiValueCreateMutable(kABPersonPhoneProperty);
ABMultiValueAddValueAndLabel(phoneNumberMultiValue ,(__bridge void*)userInfo.phoneNumbers,(__bridge void*)userInfo.phoneNumberLabel, NULL);
// Email address is a list , so create a multivalue
ABMutableMultiValueRef emailMultiValue =
ABMultiValueCreateMutable(kABPersonEmailProperty);
ABMultiValueAddValueAndLabel(emailMultiValue ,(__bridge void*)userInfo.emailAddress,(__bridge void*)userInfo.emailAddressLabel, NULL);
// Save Address Book
BOOL isContactEdited = ABAddressBookSave(addressBook, nil);
CFRelease(addressBook);
return isContactEdited;
In my above code phonenumberlabel & emailAddressLabel are label values of phone number & email address . e.g "Mobile" or "Home" etc.
I can't find method to set multivaluerefs like used for first name & lastname.
Any kind of help is appreciated. Thanks.
First, when you select the contact from the PeoplePickerNavigationController:
- (BOOL)peoplePickerNavigationController: (ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person {
self.selectedPerson = ABRecordGetRecordID(person);
(...)
}
Then on my .h
#property (nonatomic) ABRecordID selectedPerson;
// adding email to native contacts
Then go back to .m
ABAddressBookRef addressBook = ABAddressBookCreate();
CFErrorRef error = nil;
ABMutableMultiValueRef emailMultiValue = ABMultiValueCreateMutable(kABPersonEmailProperty);
bool didAddEmail = ABMultiValueAddValueAndLabel(emailMultiValue, (__bridge CFTypeRef)(email), kABOtherLabel, NULL);
if(didAddEmail){
ABRecordSetValue(ABAddressBookGetPersonWithRecordID(addressBook, self.selectedPerson),
kABPersonEmailProperty,
emailMultiValue,
nil);
} else {
NSLog(#"Error adding email: %#", error);
error = nil;
}
Then somewhere you have to save the address book somewhere in your code...
bool bSuccess = ABAddressBookSave(addressBook, &error);
if (!bSuccess) {
NSLog(#"Could not save to address book: %#", error);
}

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