I follow this instruction to add vcard data to addressbook, in my project. iOS 5.
Adding vCard data directly to the system Address Book
The code run ok, and add vcard data to adressbook in my ipad2 and iphone4s, however, xcode show this error:
thread 1 program received signal: "exc_bad_acess"
Why this error appears?
EDIT: code add.
NSString *vCardString =
#"BEGIN:VCARD\n"
#"N:Paulo;Joao\n"
#"TEL:+44 (0)9999 8888\n"
#"ADR;HOME:;;Flat 2, 43 Howitt Road, Belsize Park;London;;NW34LU;UK\n"
#"ORG:NetTek Ltd;\n"
#"TITLE:Consultant\n"
#"EMAIL:none#none.com\n"
#"URL:www.none.com\n"
#"BDAY:19001010\n"
#"END:VCARD";
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(person);
}
CFRelease(vCardPeople);
CFRelease(defaultSource);
ABAddressBookSave(book, NULL);
CFRelease(book);
I found the problem.
The problem is with the last line, probably because of ARC.
CFRelease(book);
I commented the line, and the program run normally.
I'm glad you were able to find the problem, however, I just thought I'd let you know that it's not an ARC thing but a memory leak thing. You're over-releasing data the the OS wants to release itself. Here's an explanation.
Additionally, please mark the question as answered so you can help other people find the solution. Thank you!
Related
I got issue potential leak of an object stored into address book, how to resolve it.
I create address book locally and then copyArrayofAllpeople to people1 array. people1 array used outside of method. So where should I release addressbookref. Please make suggestions.
This is my code
ABAddressBookRef addressBook = ABAddressBookCreate();
people1 = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
Use CFRelease() method.
ABAddressBookRef addressBook = ABAddressBookCreate();
people1 = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
CFRelease(addressBook);
I think it will be helpful to you.
Using the ABPersonCreateVCardRepresentationWithPeople method for export, and the ABPersonCreatePeopleInSourceWithVCardRepresentation for import, I have successfully transfered contact data between devices. However, the data in the contact's "notes" field isn't transfered.
Here's my export function:
+(NSData*)exportContactsToVcard:(NSArray*)contacts
{
NSMutableArray *people = [NSMutableArray arrayWithCapacity:contacts.count];
ABAddressBookRef ab = ABAddressBookCreate();
for (Contact *contact in contacts)
{
ABRecordRef person = ABAddressBookGetPersonWithRecordID(ab,contact.contactId);
[people addObject:(__bridge id)person];
}
NSData *vCard = (__bridge NSData*)ABPersonCreateVCardRepresentationWithPeople((__bridge CFArrayRef) people);
return vCard;
}
and part of my import function:
+(NSArray*)importContactsFromVcardData:(NSData*)vcardData
{
NSMutableArray *addedContactIds = [NSMutableArray array];
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef defaultSource = ABAddressBookCopyDefaultSource(addressBook);
NSArray *createdPeople = (__bridge_transfer NSArray*)ABPersonCreatePeopleInSourceWithVCardRepresentation(defaultSource,(__bridge CFDataRef)vcardData);
CFErrorRef error = NULL;
for (id person in createdPeople)
{
error = NULL;
ABRecordRef personRecord = (__bridge ABRecordRef)person;
NSString *notes = (__bridge NSString *)ABRecordCopyValue(personRecord, kABPersonNoteProperty);
In the last line, notes is always nil, even if the contact had notes before it was exported. All the other standard contact fields seem to be in place.
For example, if I replace the last line with:
NSString *firstName = (__bridge NSString *)ABRecordCopyValue(personRecord, kABPersonFirstNameProperty);
the firstName string will hold the contact's first name.
Any idea how I can work around this, and get the contact notes?
Thanks.
For testing purposes, you can export a vCard from Address Book. Then drag it to TextEdit to look at the various fields.
At the bottom you'll find something like this:
NOTE:This is a note!
Also, see this link for info on the vCard format:
http://en.wikipedia.org/wiki/VCard
ABPersonCreateVCardRepresentationWithPeople will only transfer the important contact details of a vCard...thats my identifying in much tests with the vCard and the iOS import-export function. It has many mistakes, e.g. if you try to import it with social networks like facebook, it won't do it with (just look in my other thread THREADLINK )
But if you try to add some vCard Information over ABNewPersonViewController, it will work perfectly.
Working on someone else's code. I am really confused about whats exactly happening in this code.
ABAddressBookRef addressBook = ABAddressBookCreate();
ABRecordRef persons = ABAddressBookGetPersonWithRecordID(addressBook, x);
CFErrorRef *error=NULL;
ABAddressBookRemoveRecord(addressBook, persons, error);
ABAddressBookSave(addressBook, error);
ABRecordRef persons = ABPersonCreate();
ABRecordSetValue(persons, kABPersonFirstNameProperty, firstName , nil);
What should be done is that, a ABRecordRef person should be created. His properties should be set and his record/details should be displayed. He should never be saved in the address book. Is this the way to do it. Need help.
Edit: Apart from setting properties to person, the following code is added to push the view controller to view the person.
MyContactDetailViewcontroller *personContactDetail = [[MyContactDetailViewcontroller alloc] init];
personContactDetail.displayedPerson = persons;
personContactDetail.passedSelectedContactData = selectedContactsOnlyData;
[self.navigationController pushViewController:personContactDetail animated:YES];
[personContactDetail release];
MyContactDetailViewcontroller subclass ABPersonViewController. Or is it more apt to use ABUnknownPersonViewController.
Do you find any cases where the contacts could be duplicated in address book
This is exactly what is happening here.. I will explain..
ABAddressBookCreate creates a new address book from data from the addressbook database, so any changes you make to ABAddressBookRef will only be saved to actual addressbook database once you call ABAddressBookSave(). so what it is doing is getting the reference for the person with recordid- x. Than you are creating a new person entry using
ABRecordRef persons = ABPersonCreate();
and than you are setting its value, but this is available to this particular object and not stored in the database unless you call... ABAddressBookSave()
hoping this helps you... :)
I am trying to create a custom addressbook on the iPhone by adding new records to the device address book (basically, merging a private contact list with the device AB). I then want to let the user select a contact, which I thought I could do with the .addressbook property of ABPeoplePickerNavigationController:
ABAddressBookRef contacts = ABAddressBookCreate();
for (PrivateUserType *user in rosterItems)
{
CFErrorRef err = NULL;
ABRecordRef ref = ABPersonCreate();
ABRecordSetValue(ref, kABPersonLastNameProperty, (CFStringRef)user.lastName, &err);
if (err != NULL)
{
NSString *errorStr = [(NSString *)CFErrorCopyDescription(err) autorelease];
NSLog(#"Can not set name: %#", errorStr);
}
...
ABAddressBookAddRecord(contacts, ref, &err);
if (err != NULL)
{
NSString *errorStr = [(NSString *)CFErrorCopyDescription(err) autorelease];
NSLog(#"Error adding XMPP roster user to addressbook: %#", errorStr);
}
}
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
picker.addressBook = contacts;
[viewController presentModalViewController:picker animated:YES];
[picker release];
The entries are successfully added to the addressbook (which I can verify if I do an ABAddressBookSave() after the loop to add everything in). However, the entries are not shown by picker (unless I save contacts, which of course saves all changes into the device addressbook).
Is there a way to do this? This is on iOS 4.3.1.
Thanks!
As Toro said, you need save any changes to database first. ABPeoplePickerNavigationController not intended to work with uncommit data or with custom data.
You can see rather fresh topic on Apple Dev Forums
https://devforums.apple.com/message/370070#370070
where similar question was asked. And guy from Apple says that "I can't see any way to do this." But he suggest filling a bug for this to implement this feature in future release of iOS.
All you can do now is code your own UI for this AddressBook from the ground :(
updated: he-he. I found your question on App Dev Forum too )))
You need to save any changes to database by ABAddressBookSave() method.
The apple doc link.
i have a problem make headache, i simply create method:
-(void) main{
for (int i = 0; i< 100;i++) {
[self getPhoneOfContact:i];
}
}
-(void)getPhoneOfContact:(NSInteger)id_contact {
ABRecordRef record = ABAddressBookGetPersonWithRecordID(addressBook,id_contact);
CFTypeRef ref1;
ref1 = ABRecordCopyValue(record,kABPersonPhoneProperty);
CFRelease(record);
CFRelease(ref1);
}
I think the memory will approximate constants because i have release memory copied, but in reality it still increasing for each loop i;
who can explain me this :(. thanks!
Your code is wrong. The ABAddressBookGetPersonWithRecordID call follows the Core Foundation 'Get Rule'. This means you do not have ownership of the return value and thus you do not have to release it.
See Core Foundation - Memory Management
It's possible that running ABAddressBookGetPersonWithRecordID and/or ABRecordCopyValue uses some autoreleased objects you don't know about, and this would cause the memory to increase. It will be released, though, when the nearest autorelease pool is drained. This is not a problem with your application.
Try to place the loop in its own autorelease pool and drain the pool after you execute the loop:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// do computation
[pool release];
Does this "reset" the memory to the initial amount?
Also, in general, try to use XCode's Instruments Memory Leaks instead of looking at memory usage - this can be only helpful, but Memory Leaks is the main tool to find, well.. memory leaks :)
I'm not sure, but I think this may be what's happening...
// 1. alloc and return a record address to record
ABRecordRef record = ABAddressBookGetPersonWithRecordID(addressBook,id_contact);
// 2. alloc and return the default CFTypeRef to ref1
CFTypeRef ref1;
// 3. copy and return the value of kABPersonPhoneProperty
ref1 = ABRecordCopyValue(record,kABPersonPhoneProperty);
// release 1
CFRelease(record);
// release 3
CFRelease(ref1);
Thus, 2 is still leaking. Maybe try doing CFTypeRef ref1 = nil or just doing it all on one line?
Does this even work for you? The actual retrieval of the info? This is what I use to retrieve the kABPersonPhoneProperty out of records.
ABMutableMultiValueRef multi = ABRecordCopyValue(person, kABPersonPhoneProperty);
for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++) {
CFStringRef phoneNumberLabel = ABMultiValueCopyLabelAtIndex(multi, i);
CFStringRef phoneNumber = ABMultiValueCopyValueAtIndex(multi, i);
// Do stuff with the info.
CFRelease(phoneNumberLabel);
CFRelease(phoneNumber);
}
CFRelease(multi);