Sunday, December 19, 2010

NULL Issues in ABContact Open Source Project

I found a nice open source project for Mac/iOS Address Book data source. The project contains several key wrapper classes: ABContact, ABGroup, and ABContactsHeler. Mac OS/iOS has extensive APIs for accessing and editing AB records, but they are all C libraries. The project provides nice Objective-C wrapper classes for those libraries.

Today, I found several bugs with multi value properties. Some NULL issues in the wrapper class ABContact.m methods have not been handled. As a result, I got EXC_BAD_ACCESS exception. Basically, if a record has no multi-value property defined, for example address property, the CFTypeRef value will be NULL. The fix is very easy: checking NULL before using CFTypeRef value. Here are my updated codes:

#pragma mark -
#pragma mark Getting MultiValue Elements
- (NSArray *) arrayForProperty: (ABPropertyID) anID
{
NSArray *items = [NSArray array];
CFTypeRef theProperty = ABRecordCopyValue(record, anID);
// the return value is NULL if no multi property is defined for the record.
// therefore, check its NULL first before getting values
// Updated by David Chu, same apply to the following methods
if (theProperty != NULL ) {
items = (NSArray *)ABMultiValueCopyArrayOfAllValues(theProperty);
CFRelease(theProperty);
[items autorelease];
}
return items;
}

- (NSArray *) labelsForProperty: (ABPropertyID) anID
{
NSMutableArray *labels = [NSMutableArray array];
CFTypeRef theProperty = ABRecordCopyValue(record, anID);
if ( theProperty != NULL ) {
for (int i = 0; i < ABMultiValueGetCount(theProperty); i++)
{
NSString *label = (NSString *)ABMultiValueCopyLabelAtIndex(theProperty, i);
[labels addObject:label];
[label release];
}
CFRelease(theProperty);
}
return labels;
}

+ (NSArray *) arrayForProperty: (ABPropertyID) anID inRecord: (ABRecordRef) record
{
NSArray *items = [NSArray array];
// Recover the property for a given record
CFTypeRef theProperty = ABRecordCopyValue(record, anID);
if (theProperty != NULL) {
items = (NSArray *)ABMultiValueCopyArrayOfAllValues(theProperty);
CFRelease(theProperty);
[items autorelease];
}
return items;
}

The original codes do not check NULL cases. With those updates, my codes resume normal. In addition to NULL checking, I also make sure there is no memory leak, as the same way as the original codes do. All the copied NSArray result are set with autorelease.

1 comments:

emmanuel said...

Thanks so much for this !