Adding contact image to address book iPhone - iphone

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

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.

Related

How to edit a ABPersonSetImageData from Address book

I am working on an iPhone application which works with AddressBook contacts. I am trying to fetch the image from address book and edit then save that image.
But I don't know how to update and save that image. Please give me a solution if anybody knows about this.
Thanx in advance.
Here's the .h file
ABAddressBookRef addressBook;
IBOutlet UILabel *lblName;
IBOutlet UIImageView *imgGet;
UIImage *imgContact;
NSString* name;
The .m file
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person {
name = [(NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty) autorelease];
lblName.text = name;
if(ABPersonHasImageData(person)) {
CFDataRef imageData = ABPersonCopyImageData(person);
imgContact = [UIImage imageWithData:(NSData *)imageData];
imgGet.image = imgContact;
CFRelease(imageData);
} else {
imgGet.image = [UIImage imageNamed:#"ABPicturePerson#2x.png"];
}
[self.navigationController dismissViewControllerAnimated:(YES) completion:nil];
return NO;
}
Here After fetching image and name from above method then i open gallery and select an image then click on below method button but image not saved or update in address book
-(IBAction)btnSaveClicked {
ABRecordRef person = ABPersonCreate();
NSData *dataRef = UIImagePNGRepresentation(imgGet.image);
CFDataRef cfdata = CFDataCreate(NULL, [dataRef bytes], [dataRef length]);
ABPersonSetImageData(person, (CFDataRef)dataRef, nil);
CFErrorRef error;
ABPersonRemoveImageData(person, &error); // <-- clean any image first from ref
//ABAddressBookSave(addressBook, &error);
ABPersonSetImageData(person, cfdata, &error);
ABAddressBookSave(addressBook, &error);
CFRelease(cfdata);
}
This link is hint for me that how to update your image..
http://davidbits.blogspot.in/2010/01/iphone-update-addressbook-contact.html
declare 1 object in .h file
NSInteger recordID;
then open contact list and for fetching the contact we use this method
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person {
recordID = ABRecordGetRecordID(person);
name = [(NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty) autorelease];
lblName.text = name;
if(ABPersonHasImageData(person)) {
CFDataRef imageData = ABPersonCopyImageData(person);
your uiimage = [UIImage imageWithData:(NSData *)imageData];
you uiimageview.image = your uiimage;
CFRelease(imageData);
} else {
you uiimageview.image = [UIImage imageNamed:#"ABPicturePerson#2x.png"];
}
[self.navigationController dismissViewControllerAnimated:(YES) completion:nil];
//[self.navigationController dismissModalViewControllerAnimated:YES];
return NO;
}
then write action for save detail or update detail
-(IBAction)btnSaveClicked
{
CFErrorRef *aberror = NULL;
ABRecordRef aRecord = ABAddressBookGetPersonWithRecordID(addressBook, recordID);
if (aRecord) {
NSData *dataRef = UIImagePNGRepresentation(your uiimage);
ABPersonSetImageData(aRecord, (CFDataRef)dataRef, nil);
}
ABAddressBookSave(addressBook, aberror);
//BOOL didAdd = ABAddressBookSave(addressBook, nil);
CFRelease(addressBook);
}
sure you will get result..
Use ABRecordRef person when you want to update:
Firstly create ABAddressBookRef:
// Request authorization to Address Book
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
Now check person has image:
if(ABPersonHasImageData(person))
{
//remove image as we want to update to new image
NSError *anError;
if(ABPersonRemoveImageData(person, &anError))
NSLog(#"removed");
else
NSLog(#"%#",[anError description]);
}
Update
UIImage *image = image here;
NSData *picData = UIImageJPEGRepresentation(image, 0.9f);
ABPersonSetImageData(person, (CFDataRef)picData, nil);
call saving function:
ABAddressBookSave(addressBookRef, nil);

unable to create a person using VCard representation

I am developing an app using XCode 4.2 and I am trying to create an ABPerson using initWithVCardRepresentation and/or ABPersonCreatePeopleInSourceWithVCardRepresentation , but I can t find a working example . can someone help?
I get the VCard in an NSString format....
Thanks
This is a full example and it works perfectly, it bases on the latest iOS 8.
First of all you should check authorization status and request access right if not, then save the vcard, let just review the code below:
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized){
NSLog(#"Authorized");
[self addVcardsIntoAddressBook:vcard];
} else{
NSLog(#"Not determined");
ABAddressBookRequestAccessWithCompletion(ABAddressBookCreateWithOptions(NULL, nil), ^(bool granted, CFErrorRef error) {
if (!granted){
NSLog(#"Just denied");
return;
}
NSLog(#"Just authorized");
[self addVcardsIntoAddressBook:vcard];
});
}
This is how to add vcard:
- (void)addVcardsIntoAddressBook:(NSData *)vcard {
CFDataRef vCardData = CFDataCreate(NULL, [vcard bytes], [vcard length]);
ABAddressBookRef book = ABAddressBookCreate();
ABRecordRef defaultSource = ABAddressBookCopyDefaultSource(book);
CFArrayRef vCardPeople = ABPersonCreatePeopleInSourceWithVCardRepresentation(defaultSource, vCardData);
for (CFIndex index = 0; index < CFArrayGetCount(vCardPeople); index++) {
ABRecordRef person = CFArrayGetValueAtIndex(vCardPeople, index);
ABAddressBookAddRecord(book, person, NULL);
CFRelease(person);
}
ABAddressBookSave(book, NULL);
}
Here it is Swift version of acoustic's answer;
let vCard : NSData // vcard
let addressBook: ABAddressBook? = ABAddressBookCreateWithOptions(nil, nil)?.takeRetainedValue()
ABAddressBookRequestAccessWithCompletion(addressBook) {
granted, error in
if !granted {
return
}
let vCardData = CFDataCreate(nil, UnsafePointer<UInt8>(vCard.bytes), vCard.length)
let defaultSource = ABAddressBookCopyDefaultSource(addressBook)
let vCardPeople = ABPersonCreatePeopleInSourceWithVCardRepresentation(defaultSource.takeUnretainedValue(), vCardData).takeRetainedValue() as NSArray
for person in vCardPeople {
ABAddressBookAddRecord(addressBook, person, nil)
}
let isSaved = ABAddressBookSave(addressBook, nil)
if isSaved{
//succesfully saved
}
else{
//not saved
}
}
I'm using this code that I found somewhere on a forum:
// Assuming your vCard is stored in vCardString as an NSString
CFDataRef vCardData = (__bridge CFDataRef)[vCardString dataUsingEncoding:NSUTF8StringEncoding];
ABAddressBookRef book = ABAddressBookCreate();
ABRecordRef defaultSource = ABAddressBookCopyDefaultSource(book);
CFArrayRef vCardPeople = ABPersonCreatePeopleInSourceWithVCardRepresentation(defaultSource, vCardData);
CFIndex index = 0;
ABRecordRef person = CFArrayGetValueAtIndex(vCardPeople, index);
I am using it and it is working fine with Vcard 2.1 and 3.0
NSString *filename = [[NSBundle mainBundle] pathForResource:#"Contacts" ofType:#"vcf"];
NSLog(#"openning file %#", filename);
NSData *stringData = [NSData dataWithContentsOfFile:filename];
NSString *vCardString = [[NSString alloc] initWithData:stringData encoding:NSUTF8StringEncoding];
CFDataRef vCardData = (__bridge CFDataRef)[vCardString dataUsingEncoding:NSUTF8StringEncoding];
ABAddressBookRef book = ABAddressBookCreate();
ABRecordRef defaultSource = ABAddressBookCopyDefaultSource(book);
CFArrayRef vCardPeople = ABPersonCreatePeopleInSourceWithVCardRepresentation(defaultSource, vCardData);
for (CFIndex index = 0; index < CFArrayGetCount(vCardPeople); index++) {
ABRecordRef person = CFArrayGetValueAtIndex(vCardPeople, index);
ABAddressBookAddRecord(book, person, NULL);
}
CFRelease(vCardPeople);
CFRelease(defaultSource);
ABAddressBookSave(book, NULL);
CFRelease(book);

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);

Why does Keychain Services return the wrong keychain content?

I've been trying to use persistent keychain references in an iPhone application. I found that if I created two different keychain items, I would get a different persistent reference each time (they look like 'genp.......1', 'genp.......2', …). However, attempts to look up the items by persistent reference always returned the content of the first item. Why should this be? I confirmed that my keychain-saving code was definitely creating new items in each case (rather than updating existing items), and was not getting any errors. And as I say, Keychain Services is giving a different persistent reference for each item.
I've managed to solve my immediate problem by searching for keychain items by attribute rather than persistent references, but it would be easier to use persistent references so I'd appreciate solving this problem.
Here's my code:
- (NSString *)keychainItemWithName: (NSString *)name {
NSString *path = [GLApplicationSupportFolder()
stringByAppendingPathComponent: name];
NSData *persistentRef = [NSData dataWithContentsOfFile: path];
if (!persistentRef) {
NSLog(#"no persistent reference for name: %#", name);
return nil;
}
NSArray *refs = [NSArray arrayWithObject: persistentRef];
//get the data
CFMutableDictionaryRef params = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(params, kSecMatchItemList, refs);
CFDictionaryAddValue(params, kSecClass, kSecClassGenericPassword);
CFDictionaryAddValue(params, kSecReturnData, kCFBooleanTrue);
CFDataRef item = NULL;
OSStatus result = SecItemCopyMatching(params, (CFTypeRef *)&item);
CFRelease(params);
if (result != errSecSuccess) {
NSLog(#"error %d retrieving keychain reference for name: %#", result, name);
return nil;
}
NSString *token = [[NSString alloc] initWithData: (NSData *)item
encoding: NSUTF8StringEncoding];
CFRelease(item);
return [token autorelease];
}
- (void)setKeychainItem: (NSString *)newToken forName: (NSString *)name {
NSData *tokenData = [newToken dataUsingEncoding: NSUTF8StringEncoding];
//firstly, find out whether the item already exists
NSDictionary *searchAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
name, kSecAttrAccount,
kCFBooleanTrue, kSecReturnAttributes,
nil];
NSDictionary *foundAttrs = nil;
OSStatus searchResult = SecItemCopyMatching((CFDictionaryRef)searchAttributes,
(CFTypeRef *)&foundAttrs);
if (noErr == searchResult) {
NSMutableDictionary *toStore = [foundAttrs mutableCopy];
[toStore setObject: tokenData forKey: (id)kSecValueData];
OSStatus result = SecItemUpdate((CFDictionaryRef)foundAttrs,
(CFDictionaryRef)toStore);
if (result != errSecSuccess) {
NSLog(#"error %d updating keychain", result);
}
[toStore release];
return;
}
//need to create the item.
CFMutableDictionaryRef params = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(params, kSecClass, kSecClassGenericPassword);
CFDictionaryAddValue(params, kSecAttrAccount, name);
CFDictionaryAddValue(params, kSecReturnPersistentRef, kCFBooleanTrue);
CFDictionaryAddValue(params, kSecValueData, tokenData);
NSData *persistentRef = nil;
OSStatus result = SecItemAdd(params, (CFTypeRef *)&persistentRef);
CFRelease(params);
if (result != errSecSuccess) {
NSLog(#"error %d from keychain services", result);
return;
}
NSString *path = [GLApplicationSupportFolder()
stringByAppendingPathComponent: name];
[persistentRef writeToFile: path atomically: NO];
[persistentRef release];
}
Turns out that using the kSecMatchItemList doesn't appear to work at all.
I did mine like this:
NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
(id)kSecClassGenericPassword, kSecClass,
persistentRef, (id)kSecValuePersistentRef,
(id)kCFBooleanTrue, kSecReturnAttributes,
(id)kCFBooleanTrue, kSecReturnData,
nil];
NSDictionary *result = nil;
OSStatus status = SecItemCopyMatching((CFDictionaryRef)query,
(CFTypeRef*)&result);
which returned the attributes and data for the persistent reference. The documentation in the header about converting a "persistent reference" into a "standard reference" makes no sense at all. Hope this helps.

Setting Address Book image for a contact doesn't seem to work

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?
All these answer didn't work.
You should simply change your line of code from:
ABAddressBookRef addressBook = ABAddressBookCreate();
to:
ABAddressBookRef addressBook = [peoplePicker addressBook];
This way you get the reference to the "address book", "person" belongs to.
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;
}
I checked your code and it doesn't work as it should. So I made 2 changes.
ABAddressBookRef libroDirec = [peoplePicker addressBook];//don't create
ABPersonSetImageData(person, (CFDataRef)UIImagePNGRepresentation(display.image), &cfError);
ABAddressBookAddRecord(libroDirec, person, &cfError);
if (ABAddressBookSave(libroDirec, nil)) {
NSLog(#"\n%s saved successfuly", _cmd);
} else {
NSLog(#"\n%s something bad happen while saving", _cmd);
}
//CFRelease(libroDirec);
Now it works as it supposed to.
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.