0

I have, under ARC, a tableview controller that reads data from the address book for every shown tableview cell. Since for performance reasons I cannot open the address book for every call to tableView:cellForRowAtIndexPath:, I open it once in viewDidLoad and to store the reference to it in a @property (nonatomic) ABAddressBookRef addressBookRef; It will be released with CFRelease(self.addressBookRef); in the dealloc method of the tableview controller.
This seems to me to be correct, but the static analyzer complains about a "Potential leak of an object" in viewDidLoad in the line of the if statement below:

- (void)viewDidLoad{
    [super viewDidLoad];
    CFErrorRef error = nil;
    self.addressBookRef = ABAddressBookCreateWithOptions (NULL, &error);
    if (self.addressBookRef == nil) {
        NSLog(@"%@: %@: Could not open addressbook", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
    }

...

Do I something wrong, or how could I get rid of the warning?

Reinhard Männer
  • 14,022
  • 5
  • 54
  • 116

2 Answers2

1

I believe I found the solution, although I am not 100% sure:
I declared the property that stores the address book reference as

@property (strong, nonatomic) id addressBookRef;

and assigned the reference to it by

self.addressBookRef = CFBridgingRelease(ABAddressBookCreateWithOptions (NULL, &error));  

This should transfer the ownership from CF to ARC.
In my code, wherever I access the address book reference, I do it using

(__bridge ABAddressBookRef)(self.addressBookRef)  

And since retain/release is now handled by ARC, the CFRelease(self.addressBookRef) in the dealloc method is no longer necessary.
And the compiler warning is gone!

Reinhard Männer
  • 14,022
  • 5
  • 54
  • 116
0

You could override setAddressBookRef: so that it retains the address book ref, and release it after assign the property.

Something like this. You'll want to check for NULL, since calling CFRetain/Release with it will cause a runtime error.

- (void)setAddressBookRef:(ABAddressBookRef)addressBook
{
    CFRetain(addressBook);
    CFRelease(_addressBookRef);
    _addressBookRef = addressBook;
}
Collin
  • 478
  • 5
  • 7
  • Thanks for your answer, but I don't understand it completely: To my mind, the problem is not an incorrect handling of retain/release. ABAddressBookCreateWithOptions creates an CF object with a retain count of 1, and this is balanced by a CFRelease in dealloc. The problem seems to be that the static analyzer is not aware that dealloc will eventually be called, so that no memory will leak. Under OSX, one could probably bridge the CF object to an NS object, so that ARC can handle it. But this is not possible in iOS. – Reinhard Männer Jan 28 '14 at 06:05
  • Normally you'd want your setter to retain the object, which raises the retain count to two, before releasing it yourself, which lowers it back to one. It'll then get lowered to zero when you release it in dealloc. If you had a regular `strong` property for an Objective-C object, that's what it would be doing for you. – Collin Jan 29 '14 at 19:08
  • I tried your solution, and it works, if the address book is released in dealloc by CFRelease(_addressBookRef);. Thanks again! – Reinhard Männer Feb 04 '14 at 07:37