ABAddressBookRemoveRecord(); occasionally not deleting as expected - ios

I have written an app that gets access to addressbook, the user is supposed to be able to delete a contact from the app and it will delete that contact from the addressbook
Sometimes this just doesn't happen, although when tracing, everything works as expect and I get notified that ABAddressBookRegisterExternalChangeCallback(); right after the delete, but when I go to contact app on the phone, the total number of contacts remain the same and that contact is still there, not deleted.
Here is the code for deletion
// this method takes and NSManagedObject which holds the id of the person that should be deleted
- (void)deleteContactFromAddressBook:(NSManagedObject *)object
{
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
NSNumber *contactID = [object valueForKey:#"contactID"];
ABRecordRef contactRef = ABAddressBookGetPersonWithRecordID(addressBook, [contactID intValue]);
NSString *firstName = (__bridge NSString *)ABRecordCopyValue(contactRef,
kABPersonFirstNameProperty);
NSString *lastName = (__bridge NSString *)ABRecordCopyValue(contactRef,
kABPersonLastNameProperty);
if (!lastName) {
lastName = #"";
}
NSLog(#"contact to be deleted - Name: %#" ,[firstName stringByAppendingString:lastName]);
BOOL deleteCheck = ABAddressBookRemoveRecord(addressBook, contactRef, NULL);
BOOL saveCheck = ABAddressBookSave(addressBook, NULL);
NSLog(#"delete check = %hhd ---------- save check = %hhd", deleteCheck, saveCheck);
NSLog(#"Contact Deleted with id: %#", contactID);
}
If you need further explanation don't hesitate to ask. I am really frustrated by this unexpected behavior and I have no clue where to look.
Thank you.

I may be wrong,as so far I've only written for OSX where I did have a similar problem, which I eventually solved. (See link below)
I've a hunch your addressBook object is just a local copy. I found I had to get the addressBook using ABAddressBook *addressBook =[ABAddressBook sharedAddressBook]; and work with the records from that, finishing as you do with [addressBook save]; Your iOS usage may be different.
(How can I get the values I set for custom properties in AddressBook to persist?)

Related

Address Book check if Contact exist in addressbook Getting crashed with EXC_BAD_ACCESS

NSArray *allContacts = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBookRef);
BOOL isExisted=FALSE;
for (id record in allContacts){
ABRecordRef thisContact = (__bridge ABRecordRef)record;
if(thisContact!=nil){
if (CFStringCompare(ABRecordCopyCompositeName(thisContact),
ABRecordCopyCompositeName(newPerson), 0) == kCFCompareEqualTo){
//The contact already exists!
isExisted=YES;
}
}
}
Above is my code to get the contacts and check if that contact is already exist in Addressbook but its getting an error at line if
(CFStringCompare(ABRecordCopyCompositeName(thisContact),
ABRecordCopyCompositeName(newPerson), 0) == kCFCompareEqualTo)
can anyone please help me..
am using ARC Enabled Project
Hi I had the same issue the problem is to check if your current new person hasn't any nil fields and before making comparison check if thisContact name field is not nil.
This is how i did:
NSString *firstName = CFBridgingRelease(ABRecordCopyValue(thisContact, kABPersonFirstNameProperty));
NSString *lastName = CFBridgingRelease(ABRecordCopyValue(thisContact, kABPersonLastNameProperty));
you can check the phone number, email if you want to make a comparison

ABAddressBook -- Search Exchange AddressBook Source?

I'm trying to create an app with a custom interface for searching through one's addressbook. Searching the local addressbook seems easy, but I cannot figure out how to search for a person/record in an Exchange addressbook source (i.e. ABSourceType == kABSourceTypeExchangeGAL). I'm using the following code to find the Exchange addressbook source and query it, but I only ever get back an empty array. I understand asking for the entire list of people in an Exchange addressbook cannot possibly return all entries, but I would expect some subset of that list when I query it. Again, instead I get an empty array.
How do you search for contacts in an Exchange addressbook source?
#define CFNIL(x) if(x){CFRelease(x); x=nil;}
//code
ABAddressBookRef _addressbook = ABAddressBookCreate();
CFArrayRef allSources = ABAddressBookCopyArrayOfAllSources(_addressbook);
ABRecordRef exchangeSource;
for(CFIndex i =0; i<CFArrayGetCount(allSources); i++)
{
ABRecordRef source = (ABRecordRef)CFArrayGetValueAtIndex(allSources, i);
NSNumber *sourceTypeNumber = (NSNumber*)((CFNumberRef)ABRecordCopyValue(source, kABSourceType));
NSString *sourceTypeName = (NSString *)((CFStringRef)ABRecordCopyValue(source, kABSourceNameProperty));
int sourceType = [sourceTypeNumber intValue];
if (sourceType == kABSourceTypeExchangeGAL)
{
exchangeSource = source;
}
[sourceTypeNumber release];
[sourceTypeName release];
}
if(exchangeSource)
{
/*
This finds matches in the local device addressbook
NSArray *people = (NSArray *)ABAddressBookCopyPeopleWithName(_addressbook, CFSTR("joe"));
for(int i=0;i<[people count]; i++)
{
ABRecordRef person = (ABRecordRef)[people objectAtIndex:i];
ABMultiValueRef emails = (ABMultiValueRef)ABRecordCopyValue(person, kABPersonEmailProperty);
NSLog(#"emails: %#",emails);
[((NSArray*)emails) release];
}
[people release];
*/
//this array is always empty
CFArrayRef search = ABAddressBookCopyArrayOfAllPeopleInSource (_addressbook,exchangeSource);
NSLog(#"%#", search);
CFNIL(search);
}
CFNIL(exchangeSource);
CFNIL(_addressbook);

iOS can't get person's image

I have two tableViewControllers. The first one has a list of contacts. The another one shows detailed person's information.
A chunk of code of first tableViewController
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef source = ABAddressBookCopyDefaultSource(addressBook);
NSArray *allPeople = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, source,kABPersonSortByFirstName);
for ( int i = 0; i < [allPeople count]; i++ )
{
...
contactClass = [[ContactClass alloc] initWithName:name surName:surName manID:[allPeople objectAtIndex:i]];
...
}
A chunck of code of second tableViewController
ABRecordRef person = (__bridge ABRecordRef)contactClass.manID;
BOOL isHasImage = ABPersonHasImageData(person);
Variable isHasImage is always false, even if contact has an avatar. I even checked this on the first tableViewController and if person has an avatar, then it returns true and image.
Does anyone knows why I can't get contacts image?
p.s. contactClass.manID is type of id. It has a correct adress, because ABMultiValueRef multiValue = ABRecordCopyValue((__bridge ABRecordRef)contactClass.manID, kABPersonPhoneProperty); returns correct value in the second tableViewController
I may be too late for a solution for you, but maybe this will help others that are stuck with the same problem.
Looks like ABPersonHasImageData() and ABPersonCopyImageDataWithFormat() don't work as expected on ABRecordRef copies (e.g. an ABContactRef from an array obtained using ABAddressBookCopyArrayOfAllPeople()), at leas on iOS 5.x. You may workaround it like this:
- (UIImage*)imageForContact: (ABRecordRef)contactRef {
UIImage *img = nil;
// can't get image from a ABRecordRef copy
ABRecordID contactID = ABRecordGetRecordID(contactRef);
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef origContactRef = ABAddressBookGetPersonWithRecordID(addressBook, contactID);
if (ABPersonHasImageData(origContactRef)) {
NSData *imgData = (NSData*)ABPersonCopyImageDataWithFormat(origContactRef, kABPersonImageFormatOriginalSize);
img = [UIImage imageWithData: imgData];
[imgData release];
}
CFRelease(addressBook);
return img;
}
Any further update on this ?
I have received complaints for some user not able to see thumbnail for a few contacts. Mostly it works fine, Is there any special case in which thumbnails aren't returned.
I am using the following piece of code:
- (instancetype)initWithABContact:(ABRecordRef)contact {
NSData *iThumbnailData = nil;
if (ABPersonHasImageData(contact)) {
iThumbnailData =
CFBridgingRelease(ABPersonCopyImageDataWithFormat(contact, kABPersonImageFormatThumbnail));
}
}

How to use ABUnknownPersonViewController with generated data entered intially?

This is very specific case. I believe someone had already solved this somewhere, but it's not easy for me to find it.
The situation:
1 ) an object will return NSString objects for name address1, address2, phone:
[anObject name];
[anObject address1];
[anObject address2];
[anObject name];
2 ) I would like to use these objects to prepare ABUnknownPersonViewController with initially entered values, so the user will not have to enter them before saving them in Address Book.
I have looked at iOS documents and searched through Google and StackOverflow, can't find the right answer for this simple situation.
Can anyone guide me on this?
Found an answer: It's nicely documented in iOS Developer Library:
http://developer.apple.com/library/ios/#samplecode/QuickContacts/Listings/Classes_QuickContactsViewController_m.html#//apple_ref/doc/uid/DTS40009475-Classes_QuickContactsViewController_m-DontLinkElementID_6
Here is a sample code I implemented to return a ABPersonRecordRef as an object. The error I had experienced was related to not retaining the ABPersonRecordRef object after returning it.
- (id)personRecordUsingModelObj:(id)modelObj {
ABRecordRef aContact = ABPersonCreate();
CFErrorRef anError = NULL;
NSString *name = [NSString stringWithFormat:#"%#", [modelObj name]];
ABRecordSetValue(aContact, kABPersonOrganizationProperty, name, &anError);
ABMultiValueRef phone = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMultiValueAddValueAndLabel(phone, [modelObj phone], kABPersonPhoneMainLabel, NULL);
ABRecordSetValue(aContact, kABPersonPhoneProperty, phone, &anError);
CFRelease(phone);
NSString *address = [NSString stringWithFormat:#"%# %#", [modelObj addr1], [modelObj addr2]];
NSMutableDictionary *dictionaryAddress = [[NSMutableDictionary alloc] initWithCapacity:0];
[dictionaryAddress setObject:address forKey:(NSString *)kABPersonAddressStreetKey];
[dictionaryAddress setObject:#"us" forKey:(NSString *)kABPersonAddressCountryCodeKey];
ABMutableMultiValueRef address = ABMultiValueCreateMutable(kABDictionaryPropertyType);
ABMultiValueAddValueAndLabel(address, dictionaryAddress, kABPersonAddressStreetKey, NULL);
[dictionaryAddress release];
ABRecordSetValue(aContact, kABPersonAddressProperty, address, &anError);
CFRelease(address);
if (anError) {
aContact = nil;
}
[(id)aContact autorelease];
return (id)aContact;
}

Question regarding errand on UITableView creation from iPhone Addressbook

I have a question regarding the AddressBook Framework for iOS. The situation is as follows:
I'm trying recreate the contacts view from the phone application, but I want to show the contact's phone numbers in the same view. So if a contact has more than one number, his name will be in the TableView multiple times, each time with a different number.
I am trying to accomplish that by extracting all the information I need when the view loads and after that, populate the TableView with the appropriate values from an NSArray consisting of NSDictionaries containing the contact's information.
This works great except for one thing... The contact's phonenumbers and labels are read correctly and stored in the dictionary, but when I read them out later, they seem to have vanished.
Here's my code for generating the NSDictionaries, I bet it's some kind of memory management error or something completly stupid. I hope anyone can help me, thanks a lot in advance!
persons = [[NSMutableArray alloc] init];
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef source = ABAddressBookCopyDefaultSource(addressBook);
NSArray *people = (NSArray *)ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, source, kABPersonSortByLastName);
for (id record in people)
{
ABMultiValueRef numbers = ABRecordCopyValue((ABRecordRef)record, kABPersonPhoneProperty);
for (CFIndex i = 0; i < ABMultiValueGetCount(numbers); ++i) {
CFStringRef label = ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(numbers, i));
CFStringRef number = ABMultiValueCopyValueAtIndex(numbers, i);
CFStringRef firstNameRef = ABRecordCopyValue((ABRecordRef)record, kABPersonFirstNameProperty);
CFStringRef lastNameRef = ABRecordCopyValue((ABRecordRef)record, kABPersonLastNameProperty);
CFDataRef imageDataRef = ABPersonCopyImageDataWithFormat((ABRecordRef)record, kABPersonImageFormatThumbnail);
NSString *firstName = [NSString stringWithFormat:#"%#", firstNameRef];
NSString *lastName = [NSString stringWithFormat:#"%#", lastNameRef];
NSString *pLabel = [[NSString alloc] initWithFormat:#"%#", label];
NSString *pNumber = [NSString stringWithFormat:#"%#", number];
UIImage *image = [UIImage imageWithData:(NSData*)imageDataRef];
NSDictionary *personDict = [NSDictionary dictionaryWithObjectsAndKeys:firstName, #"firstName", lastName, #"lastName", image, #"image", pNumber, #"phoneNumber", pLabel, #"label", nil];
NSLog(#"In %# - %#", pLabel, pNumber);
[persons addObject:personDict];
CFRelease(firstNameRef);
CFRelease(lastNameRef);
//CFRelease(imageDataRef);
CFRelease(label);
CFRelease(number);
}
}
CFRelease(addressBook);
CFRelease(source);
[people release];
Finally could resolve this myself. Apparently I was adding some nil-images to the dictionaries which they couldn't handle.

Resources