I was working around AddressBook framework when I've found out some memory leak of different types in my application :
Leaked Object # Address Size Responsible Library Responsible Frame
__NSCFArray 8 < multiple > 256 Bytes AddressBook ABCMultiValueInsertAndCreateIdentifier
__NSCFString 7 < multiple > 224 Bytes AppSupport _sqliteStatementApplyValuesFromRecordWithNullValue
Malloc 32 Bytes 8 < multiple > 256 Bytes AddressBook ABCMultiValueInsertAndCreateIdentifier
__NSCFArray 8 < multiple > 256 Bytes AddressBook ABCMultiValueInsertAndCreateIdentifier
ABCMultiValue 8 < multiple > 256 Bytes AddressBook ABCMultiValueCreate
Malloc 32 Bytes 7 < multiple > 224 Bytes AddressBook ABCMultiValueInsertAndCreateIdentifier
__NSCFArray 7 < multiple > 224 Bytes AddressBook ABCMultiValueInsertAndCreateIdentifier
Malloc 32 Bytes 5 < multiple > 160 Bytes AddressBook ABCMultiValueInsertAndCreateIdentifier
Here's my code :
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person {
SDAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
ABMultiValueRef multiRef = ABRecordCopyValue(person, kABPersonPhoneProperty);
NSString *number = (__bridge NSString *) ABMultiValueCopyValueAtIndex(multiRef, 0);
NSString *firstname = (__bridge NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString *lastname = (__bridge NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
number = (number ? number : @"");
firstname = (firstname ? firstname : @"");
lastname = (lastname ? lastname : @"");
NSDictionary *dic = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:number, firstname, lastname, nil] forKeys:[NSArray arrayWithObjects:kSDPhoneNumberKey, kSDFirstnameKey, kSDLastnameKey, nil]];
NSMutableArray *numberArray = [NSMutableArray arrayWithArray:appDelegate.contactArray];
[numberArray addObject:dic];
[appDelegate setContactArray:numberArray];
[self.tableView reloadData];
[self dismissModalViewControllerAnimated:YES];
return NO;
}
Do someone know which lines are responsible for these leaks ?
In general, any Core Foundation method that has Copy
or Create
in the name should either transfer ownership to your ARC objects or you must call CFRelease
yourself. Thus, you should transfer ownership for your three NSString
objects, and manually release multiRef
.
To transfer ownership to ARC you should use CFBridgingRelease
, which according to WWDC 2012 - Modern Objective-C (about 37:35 into the video), is now preferred over the previous technique, __bridging_transfer
(even though, behind the scenes, they're the same thing).
Anyway, the declarations of your three NSString
objects should be:
NSString *number = CFBridgingRelease(ABMultiValueCopyValueAtIndex(multiRef, 0));
NSString *firstname = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastname = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));
This is equivalent to:
NSString *number = (__bridge_transfer NSString *) ABMultiValueCopyValueAtIndex(multiRef, 0);
NSString *firstname = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString *lastname = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
Also, don't forget to release multiRef
, too:
CFRelease(multiRef);
By the way, if you ran the static analyzer, I believe it would have pointed these out for you. Choose "Analyze" from the "Product" menu, or press shift+command+B.