My app asks users to select one of their contacts and then one of the contact’s addresses. I want to generate a “display name” to use to refer to this address: for example, if the user selects one of John Smith’s addresses, the display name is “John Smith” and my UI will refer to his address as “John Smith’s address”. The algorithm for extracting this name from the address record is as follows:
- If the contact is a business, use the business’s name.
- If there is a first name and a last name, use “firstname lastname”.
- If there is a first name use the first name.
- If there is a last name use the last name.
- Use the string “Selected Contact”.
I have all this logic implemented. The problem is that I sometimes see crashes (KERN_INVALID_ADDRESS
) on one of the two marked lines. My app uses ARC, and I don’t have a lot of experience with Core Foundation, so I assume I’m doing the memory management or bridging incorrectly. Can anyone tell me what I’m doing wrong, and how to fix the crashes? The relevant two methods are as follows:
- (BOOL) peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef) person
property:(ABPropertyID) property
identifier:(ABMultiValueIdentifier) identifier
{
[self dismissViewControllerAnimated:YES completion:NULL];
CFTypeRef address = ABRecordCopyValue(person, property);
NSArray *addressArray = (__bridge_transfer NSArray *)ABMultiValueCopyArrayOfAllValues(address);
CFRelease(address);
NSDictionary *addressDict = [addressArray objectAtIndex:0];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressDictionary:addressDict completionHandler:^(NSArray *placemarks, NSError *error) {
if (error || !placemarks || [placemarks count] == 0) {
// tell the user that there was an error
} else {
NSString *name = contactName(person);
NSString *addressName = [NSString stringWithFormat:@"%@’s address", name];
// use `addressName` to refer to this address to the user
}
}];
return NO;
}
NSString* contactName(ABRecordRef person)
{
NSString *name;
// some crashes occur on this line:
CFNumberRef contactType = ABRecordCopyValue(person, kABPersonKindProperty);
if (contactType == kABPersonKindOrganization)
name = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonOrganizationProperty);
if (!name || [name length] == 0 || contactType == kABPersonKindPerson) {
// other crashes occur on this line:
NSString *firstName = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString *lastName = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
if (firstName && [firstName length] > 0 && lastName && [lastName length] > 0)
name = [NSString stringWithFormat:@"%@ %@", firstName, lastName];
else if (firstName && [firstName length] > 0)
name = firstName;
else if (lastName && [lastName length] > 0)
name = lastName;
if (!name || [name length] == 0)
name = @"Selected Contact";
}
CFRelease(contactType);
return name;
}