views:

897

answers:

2

I'm trying to set the contact image with the code below. I am not seeing any errors, and the image is not saved to the contact entry in the address book. Please help! I must be doing something wrong...

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
{
[abcontroller setDisplayedPerson:person];

UIImage *im = [UIImage imageNamed:@"image1.jpg"];
NSData *dataRef = UIImagePNGRepresentation(im);
CFErrorRef error;
ABAddressBookRef addressBook = ABAddressBookCreate(); 

NSLog(@"Error:",error);
    if (ABPersonSetImageData(person, (CFDataRef)dataRef, &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");
        }


    }
    else {
        NSLog(@"Error saving contact photo %@", error);
    }
ABAddressBookSave(addressBook, &error);

[self dismissModalViewControllerAnimated:YES];    

return NO;
}

Here is my output log:

2010-01-17 21:58:35.465 Error:
2010-01-17 21:58:35.504 Set contact photo <ABPeoplePickerNavigationController: 0x19e9b0>
2010-01-17 21:58:43.497 No changes made to address book
2010-01-17 21:58:44.724 Saved

I'm not sure why the error object is logging as an ABPeoplePickerNavigationController object?

+1  A: 

Regarding I'm not sure why the error object is logging as an ABPeoplePickerNavigationController object? -- because you're not properly initialising the error here:

CFErrorRef error;

Assign nil here, or it will have a random (or more precisely, some previous memory) value, incidentally pointing to an ABPeoplePickerNavigationController object.

Regarding the merits: are you sure the reference to person you have passed to your method is valid in the context of the address book? I would try to use a function such as ABAddressBookGetPersonWithRecordID first, instead of passing ABPersonRefs around and expecting them to be valid for different address book references.

Adam Woś
Brilliant. My error is now Null, meaning that I guess there was no error. So, I wonder why the image isn't being saved...?
mac_55
Please see the last change in my question. Try to change an image of a person you get from the address book you create within this method. If this works, that means you can't just re-use ABPersonRefs and have to rely on record IDs or something similar.
Adam Woś
So, I need to return the record ID of the ABPersonRef I get from the picker...and then use ABAddressBookGetPersonWithRecordID to perform the setimagedata on? :)
mac_55
Basically, yes. Disclaimer: I haven't done it myself, but my gut tells me it's certainly worth a try to investigate.
Adam Woś
Aha! It works! Thank you so much :) If you don't mind explaining, I'd be interested to know what's going on behind the scenes - howcome the addressbook is context sensitive? Also, I have an odd feeling I need to release all of these objects, right?
mac_55
Adam Woś
As for the memory - yes, you have to release the address book (because the name of the method has `Create` in it). See this guide http://developer.apple.com/iphone/library/documentation/ContactData/Conceptual/AddressBookProgrammingGuideforiPhone/300-BasicObjects/BasicObjects.html#//apple_ref/doc/uid/TP40007744-CH3-SW1 to working with AB objects - it has a sample code which shows `CFRelease` at the end.
Adam Woś
Oh, by the way, the guide I linked to previously says: **Important: Record objects cannot be passed across threads safely. Instead, you should pass the corresponding record identifier. See “Using Record Identifiers” for more information.** This implies what I hinted at about not using these objects not only after you destroy the book, but even while it's still alive, but in a different thread.
Adam Woś
Brilliant, thanks!
mac_55
+1  A: 

Hi, I have also try to use to set the image (Photo) of current selected person but it display massage to saved successfully but in real it dose not work!!!

after the digging out the code and the documents provided by Apple SDK, i have some up with the following solution.

Please check out the below code. its really working fine for me and hope for you also.

  • (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person { @try { CFErrorRef cfError = nil;

    if (ABPersonHasImageData(person)) {
        NSLog(@"%s has an image", _cmd);
    
    
    
    //theAlert = [[UIAlertView alloc] initWithTitle:@"Contact already has an image" message:@"Are you sure you want to overwrite it?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Overwrite"];
    //[theAlert show];
    //[theAlert release];
    //Note: We do not yet handle the answer to this question
    
    } // Just a sanity check if ((nil == [imageView image]) || (nil == UIImagePNGRepresentation([imageView image]))) { NSLog(@"%s NIL STUFF", _cmd); } // Not sure I even need to create and save an address book // Cf. https://devforums.apple.com/message/27512#27512 ABAddressBookRef libroDirec = ABAddressBookCreate(); ABPersonSetImageData(person, (CFDataRef) (UIImageJPEGRepresentation([imageView image], 1.0f)), &cfError); ABAddressBookAddRecord(libroDirec, person, &cfError); if (ABAddressBookSave(libroDirec, nil)) { NSLog(@"%s saved successfuly", _cmd); } else { NSLog(@"%s something bad happen while saving", _cmd); } CFRelease(libroDirec);

    } @catch (NSException * e) {

    } @finally {

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

    return NO;

}

Abu Bashar