Reading email address from contacts fails with weird memory issue
Asked Answered
H

2

5

I'm stumped.

I'm trying to get a list of all the email address a person has. I'm using the ABPeoplePickerNavigationController to select the person, which all seems fine. I'm setting my

ABRecordRef personDealingWith;

from the person argument to

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier {

and everything seems fine up till this point. The first time the following code executes, all is well. When subsequently run, I can get issues. First, the code:

// following line seems to make the difference (issue 1)
// NSLog(@"%d", ABMultiValueGetCount(ABRecordCopyValue(personDealingWith, kABPersonEmailProperty)));

// construct array of emails
ABMultiValueRef multi = ABRecordCopyValue(personDealingWith, kABPersonEmailProperty);
CFIndex emailCount = ABMultiValueGetCount(multi);

if (emailCount > 0) {
    // collect all emails in array
    for (CFIndex i = 0; i < emailCount; i++) {
        CFStringRef emailRef = ABMultiValueCopyValueAtIndex(multi, i);
        [emailArray addObject:(NSString *)emailRef];
        CFRelease(emailRef);
    }
}

// following line also matters (issue 2)
CFRelease(multi);

If compiled as written, the are no errors or static analysis problems. This crashes with a

*** -[Not A Type retain]: message sent to deallocated instance 0x4e9dc60

error.

But wait, there's more! I can fix it in either of two ways.

Firstly, I can uncomment the NSLog at the top of the function. I get a leak from the NSLog's ABRecordCopyValue every time through, but the code seems to run fine.

Also, I can comment out the

CFRelease(multi);

at the end, which does exactly the same thing. Static compilation errors, but running code.

So without a leak, this function crashes. To prevent a crash, I need to haemorrhage memory. Neither is a great solution.

Can anyone point out what's going on?

Horatia answered 10/4, 2010 at 10:34 Comment(0)
H
13

It turned out that I wasn't storing the ABRecordRef personDealingWith var correctly. I'm still not sure how to do that properly, but instead of having the functionality in another routine (performed later), I'm now doing the grunt-work in the delegate method, and using the derived results at my leisure. The new (working) routine:

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person {
    // as soon as they select someone, return
    personDealingWithFullName = (NSString *)ABRecordCopyCompositeName(person);
    personDealingWithFirstName = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
    // construct array of emails
    [personDealingWithEmails removeAllObjects];
    ABMutableMultiValueRef multi = ABRecordCopyValue(person, kABPersonEmailProperty);
    if (ABMultiValueGetCount(multi) > 0) {
        // collect all emails in array
        for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++) {
            CFStringRef emailRef = ABMultiValueCopyValueAtIndex(multi, i);
            [personDealingWithEmails addObject:(NSString *)emailRef];
            CFRelease(emailRef);
        }
    }
    CFRelease(multi);
    return NO;
}
Horatia answered 27/6, 2011 at 4:25 Comment(0)
P
0

I ran into a similar problem. The problem might lie at how you set your

ABRecordRef personDealingWith;

It seems that you can't just do:

ABRecordRef personDealingWith = person;

Because personDealingWith remains null. Instead what I did is:

ABRecordID personID = ABRecordGetRecordID(person);
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
personDealingWith = ABAddressBookGetPersonWithRecordID(addressBook, personID);
Potted answered 16/6, 2014 at 2:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.