Question

I am developing application which changes the contact picture of the contact when i select any contact from the contact picker .

Here is the code I have implemented so far,

(BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
{
    CFErrorRef error=nil;
    ABAddressBookRef addressBook = ABAddressBookCreate();
    NSString *path1 = [[NSBundle mainBundle] pathForResource:@"birthday.jpg" ofType:nil];
    UIImage *img = [UIImage imageWithContentsOfFile:path1];
    NSData *dataRef = UIImagePNGRepresentation(img);

    CFDataRef cfDataRef = CFDataCreate(NULL, [dataRef bytes], [dataRef length]);

   if(ABPersonHasImageData(person))
   {
       ABPersonRemoveImageData(person, &error);
       ABAddressBookSave(addressBook, &error);
   }
    if (ABPersonSetImageData(person,cfDataRef, &error))
    {
        NSLog(@"Set contact photo %@", error);

        if (ABAddressBookHasUnsavedChanges(addressBook))
        {
            NSLog(@"Changes made to address book");
        }
        else {
            NSLog(@"No changes made to address book");
        }
        if (ABAddressBookSave(addressBook, &error))
        {
            NSLog(@"Saved");
        }
        else {
            NSLog(@"Not saved");
        }       
    }

    CFRelease(cfDataRef);

    // TODO: release peoplePicker (and refactor code to not have it global)
    [self dismissModalViewControllerAnimated:YES];

    return NO;

}

But when I debug and look at ABAddressBookHasUnsavedChanges it is returning false and image is not getting set to the contact. What might be the reason?

I wrote this method in shouldContinueAfterSelectingPerson; I have checked the image and it's not null and ABPersonSetImageData is returning TRUE.

I have updated the code , checked for the image set already , if yes then i am removing that image and saving the saving the address book and relased CFDataRef.

But still its not working

Update:2 
 I have edited the code , please look at the changes. 

I have written all my code in this method
-(BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person { } ,
So definately there will be person who is already in address book . But i tried according to above code still that ABAddressBookHasUnsavedChanges returning false

Was it helpful?

Solution

You are creating the data wrong - you should be doing it like this.

UIImage *img = [UIImage imageWithContentsOfFile:path1];
NSData *dataRef = UIImagePNGRepresentation(img);
CFDataRef cfDataRef = CFDataCreate(NULL, [dataRef bytes], [dataRef length]);

Also try setting a break point somewhere in the beginning and check if something isn't nil or doesn't have wrong value.

UPDATE

I have tried it in actual Xcode, just to test. The reason why your code tells you that address book has no unsaved changes is because you haven't added the record inside it yet - otherwise you are setting an image on a contact that hasn't been added to address book yet (that is not a problem, you can do that without any problems, but the contact itself is not in the address book until you save it). So the magical line of code for you will probably be this:

ABAddressBookAddRecord(addressBook, person, &error);

This is the full code I've been using.

   CFErrorRef error = nil;
    ABAddressBookRef addressBook = ABAddressBookCreate();
    ABRecordRef person = ABPersonCreate();
    NSString *path1 = [[NSBundle mainBundle] pathForResource:@"sky_main" ofType:@"jpg"];

    UIImage *img = [UIImage imageWithContentsOfFile:path1];
    NSData *dataRef = UIImagePNGRepresentation(img);
    CFDataRef cfDataRef = CFDataCreate(NULL, [dataRef bytes], [dataRef length]);

    if (ABPersonHasImageData(person)) {
        ABPersonRemoveImageData(person, &error);
        ABAddressBookSave(addressBook, &error);
    }
    ABAddressBookAddRecord(addressBook, person, &error);

    if (ABPersonSetImageData(person, cfDataRef, &error)) {
        if (ABAddressBookHasUnsavedChanges(addressBook)) {
            NSLog(@"has unsaved changes");
        } else {
            NSLog(@"nothing to save");
        }
        if (ABAddressBookSave(addressBook, &error)) {
            NSLog(@"saved");
        } else {
            NSLog(@"not saved");
        }
    }


    ABUnknownPersonViewController *ctr = [[ABUnknownPersonViewController alloc] init];
    ctr.unknownPersonViewDelegate = nil;
    ctr.displayedPerson = person;
    ctr.allowsAddingToAddressBook = YES;
    ctr.allowsActions = YES;
    ctr.hidesBottomBarWhenPushed = YES;

    // [[[CCDirector sharedDirector] view] addSubview:ctr.view];
    CFRelease(person);
    CFRelease(addressBook);

I am also using the AddressBookUI, but you don't have to use it (I just wanted to see the changes to the unsaved contact).

UPDATE 2

Ok, just created a new project just to try. It looks like the problem was actually with the ABAddressBookRef. You have to get that from the peoplePicker argument of the delegate method. Since it is the delegate method you don't have to add the record because it already exists. This is the code that has to work (tried it 2 minutes ago). Let me know :)

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person {

    CFErrorRef error = nil;
    ABAddressBookRef addressBook = peoplePicker.addressBook;
    NSString *path1 = [[NSBundle mainBundle] pathForResource:@"cat" ofType:@"jpg"];

    UIImage *img = [UIImage imageWithContentsOfFile:path1];
    NSData *dataRef = UIImagePNGRepresentation(img);
    CFDataRef cfDataRef = CFDataCreate(NULL, [dataRef bytes], [dataRef length]);

    if (ABPersonHasImageData(person)) {
        ABPersonRemoveImageData(person, &error);
        ABAddressBookSave(addressBook, &error);
    }

    if (ABPersonSetImageData(person, cfDataRef, &error)) {
        if (ABAddressBookHasUnsavedChanges(addressBook)) {
            NSLog(@"has unsaved changes");
        } else {
            NSLog(@"nothing to save");
        }
        if (ABAddressBookSave(addressBook, &error)) {
            NSLog(@"saved");
        } else {
            NSLog(@"not saved");
        }
    }

    CFRelease(addressBook);

    return YES;
}

Btw., since it is the delegate method do not release the person otherwise it will crash horribly - just kidding, it will crash, because it tries to access memory that doesn't exist.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top