问题
I did Analyze and got potential leak of an object stored into warning in my code below
+ (ABAddressBookRef)getABAddressBookRef {
unsigned long long lastAddressBookGeneration = _addressBookGeneration;
unsigned long long addressBookGeneration =[[NSThread currentThread].threadDictionary[kAddressBookGeneration] unsignedLongLongValue];
ABAddressBookRef addressBook = (__bridge ABAddressBookRef)[NSThread currentThread].threadDictionary[kAddressBook];
if (addressBook == nil || (addressBookGeneration != lastAddressBookGeneration)) {
if (addressBook) {
if ([NSThread isMainThread]) {
ABAddressBookUnregisterExternalChangeCallback(addressBook,_ExternalChangeCallback, nil);
}
[[NSThread currentThread].threadDictionary removeObjectForKey:kAddressBook];
}
addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
if (addressBook != nil) {
if ([NSThread isMainThread]) {
ABAddressBookRegisterExternalChangeCallback(addressBook,_ExternalChangeCallback, nil);
}
[NSThread currentThread].threadDictionary[kAddressBook] = (__bridge id) addressBook;
[NSThread currentThread].threadDictionary[kAddressBookGeneration] = [NSNumber numberWithUnsignedLongLong:lastAddressBookGeneration];
}
}
return addressBook;
}
I looked around SO and found the problem could be ABAddressBookCreateWithOptions(NULL, NULL); I probably need to call CFRelease() after calling that. But then, my next question came up: in this method, I need to return addressBook. How can I achieve both 1) return the ABAddressBookRef 2) properly call CFRelease() so I don't get the memory leak warning?
Does this make any sense?
+ (ABAddressBookRef)getABAddressBookRef {
unsigned long long lastAddressBookGeneration = _addressBookGeneration;
unsigned long long addressBookGeneration =[[NSThread currentThread].threadDictionary[kAddressBookGeneration] unsignedLongLongValue];
ABAddressBookRef addressBook = (__bridge ABAddressBookRef)[NSThread currentThread].threadDictionary[kAddressBook];
if (addressBook == nil || (addressBookGeneration != lastAddressBookGeneration)) {
if (addressBook) {
if ([NSThread isMainThread]) {
ABAddressBookUnregisterExternalChangeCallback(addressBook,_ExternalChangeCallback, nil);
}
[[NSThread currentThread].threadDictionary removeObjectForKey:kAddressBook];
}
ABAddressBookRef newAddressBook = ABAddressBookCreateWithOptions(NULL, NULL);
addressBook = newAddressBook;
if (newAddressBook != nil) {
if ([NSThread isMainThread]) {
ABAddressBookRegisterExternalChangeCallback(newAddressBook, _ExternalChangeCallback, nil);
}
[NSThread currentThread].threadDictionary[kAddressBook] = (__bridge id) newAddressBook;
[NSThread currentThread].threadDictionary[kAddressBookGeneration] = [NSNumber numberWithUnsignedLongLong:lastAddressBookGeneration];
CFRelease(newAddressBook);
}
}
return addressBook;
}
回答1:
you can simulate autorelease easily
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0), dispatch_get_main_queue(), ^{
CFRelease(newAddressBook);
});
来源:https://stackoverflow.com/questions/22600766/whats-the-correct-way-of-releasing-an-object-when-it-also-needs-to-be-returned