Do I need to release a Core Foundation objects to clear up memory? And if so, how?
For example, in the code:
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef peopleArray = ABAddressBookCopyArrayOfAllPeople(addressBook);
do I need to release peopleArray? What about addressBook?
Yes, in CoreFoundation you have to release anything with Create or Copy in the name. You do this with CFRelease(). In your case, you should be releasing both the array and the address book references.
The rules for memory management in Core Foundation are similar to those in Cocoa: if the method that returns a reference contains the words "create" or "copy", you own the reference and must call CFRelease() on that reference to relinquish ownership. Otherwise, you do not own the reference and must call CFRetain to take ownership (necessarily requiring a subsequent CFRelease to relinquish that new ownership). These rules, as taken from the Memory Management Programming Guide for Core Foundation are:
If you create an object (either
directly or by making a copy of
another object—see “The Create
Rule”), you own it.
If you get an
object from somewhere else, you do
not own it. If you want to prevent it
being disposed of, you must add
yourself as an owner (using
CFRetain).
If you are an owner of an
object, you must relinquish ownership
when you have finished using it
(using CFRelease).
In your example, both the addressBook and the peopleArray must be released. Since there is no autorelease equivalent in Core Foundation, if you are returning the a reference from a method, return the array without releasing it. You should (unless you're being evil) then include "create" in the method name to indicate to the caller that they now own a reference to the returned object. In this case, CFArray is toll-free bridged to NSCFArray, an Objective-C object that inherits from NSObject. You can thus cast peopleArray to an NSArray* and autorelease that, if you need to return it from a function/method:
return [(NSArray*)peopleArray autorelease];
Note that this only works for toll-free bridged classes. My understanding is that it's rather difficult to make your own toll-free bridged classes and only the primitive (string, array, etc.) CF classes are toll-free bridged, so this approach won't work always. Finally, if you can avoid using autorelease (i.e. you can make your memory management more explicit), that's probably always a good thing.
Another small point that no-one has mentioned yet, some CF classes have a "toll-free bridge" with their NS counterpart. CFString and NSString, CFArray and NSArray are both examples. This is relevant as you can just use release with these classes.
See this other StackOverflow question for more information.
I would suggest reading Apple's guide on Core Foundation memory management for an in-depth discussion of this. They have a similar guide for general Cocoa memory management as well.
To release a CF object, you would call the CFRelease function.
For ARC you can use.
return (__bridge_transfer NSArray*)peopleArray;
"__bridge_transfer" will transfer the ownership to ARC and therefore you don't need any further release call.
Related
Memory management says we must release an object created with alloc. Consider this typical example code.
XYZClass *obj = [[XYZClass alloc] init];
// use obj
[obj release];
But in this example, obj may not be the object returned from alloc, as Apple's documentation says
Note: It’s possible for init to return a different object than was created by alloc, so it’s best practice to nest the calls as shown.
So this typical example seems to release the object returned from init, breaking memory management rules, and not release the object returned from alloc, further breaking the rules.
How is this typical example valid?
First of all you code uses manual memory management, that is something I would not recommend, since Xcode 4.2 for OS X v10.6 and v10.7 (64-bit applications) and for iOS 4 and iOS we have support for Automatic Reference Counting (ARC) is a compiler feature that provides automatic memory management of Objective-C objects. See Transitioning to ARC Release Notes :
Instead of your having to remember when to use retain, release, and
autorelease, ARC evaluates the lifetime requirements of your objects
and automatically inserts appropriate memory management calls for you
at compile time. The compiler also generates appropriate dealloc
methods for you.
With regards to your specific question, the fact that init might return a different object does not break the memory management, because that different object will use the same allocation. This is quite common for class clusters that the initializer might return a internal subclass.
I'm writing a C++ application using Metal API (objective C) and MRC (Manual Reference Counting). I have a very limited experience with ObjC. Most of the Metal API objects are defined as protocols and created as an object returned from C-function or other object's method (ex. MTLDevice newBufferWithLength). To know how to release objects created this way I need to know if they have been set autoreleased or not (I can't call release an autoreleased object with retain count 1 for instance). The problem is I can't find any description in Metal API documentation which would answer this question. I've only read in user guide that all so called lightweight objects are created autoreleased. There are three examples of autoreleased objects but not sure if I can just assume that rest of the objects are not autoreleased. In cocoa many objects also may be created without alloc+init, being returned from a static method (ex NSString string) so the problem seems not to be only Metal related.
Thank you for your help.
The usual Objective-C rule is that creating scope is also responsible to release object. So, in virtually all cases, except well-documented exceptions, returned object is autoreleased (both returned through return value or out-arguments). More correct way to see it is that object is always returned with +0 scope-local retain count, so you are expected to retain it if needed. Reading the manual it seems that Metal API is one of Apple's frameworks, so it should follow this rule unless warned with bold statements. C functions in Objective-C are also expected to behave that way. (There is no difference between a method and a function in terms of resource management.)
For that "alloc-init vs. [NSString string]" part: MRC code either returns [NSString string], which is already +0, or [[[NSString alloc] init] autorelease]. Otherwise it breaks the convention. Exceptions are -[init] and +[new...] methods itself that return +1. Under ARC there is no difference between alloc-init/string, because ARC knows the convention and does the right thing, optimizing excessive retains/releases where possible.
Also note that -[retainCount] is meaningless and "considered harmful", because you never know how many retain-autorelease calls were performed and what objc-runtime accounting is in effect even with your own objects.
ARC is really a great option unless you're writing some sort of Objective-C -to- Whatever bridge, where retain counts and/or cycles must be managed explicitly due to lack of context. It doesn't take anything from you, giving in most cases a big advantage of not managing resources at all.
I'm using ARC, and my application compiles and works without crashing. However, when I run an Analyze build, I am seeing these warnings. I come from PHP and JavaScript so naturally I have no idea what to do to fix this stuff. Can anyone help me out?
ARC needs some help when dealing with Core Foundation. Try this:
NSArray *linkedPeople = (__bridge_transfer NSArray *)ABPersonCopyArrayOfAllLinkedPeople(person);
and
NSDictionary *personDictionary = (__bridge_transfer NSDictionary *)(ABMultiValueCopyValueAtIndex(addressFromPerson, 0));
__bridge_transfer tells ARC that a non-Objective-C (i.e., Core Foundation) pointer is being moved to an Objective-C pointer, and it allows ARC to take ownership of the object for memory management purposes. CF functions with the word "copy" in them produce an object reference with a +1 reference count. If you don't explicitly call CFRelease() on the object later, then it will leak. Using __bridge_transfer, however, lets ARC do this for you.
(Note: I didn't test this, but I believe those are the issues that the static analyzer is complaining about.)
Yes, you can use:
NSArray *linkedPeople = (__bridge_transfer NSArray *)ABPersonCopyArrayOfAllLinkedPeople(person);
But Apple now recommends using:
NSArray *linkedPeople = CFBridgingRelease(ABPersonCopyArrayOfAllLinkedPeople(person));
It does the same thing, but Apple recommends you use the latter.
See WWDC 2012 session 405, 37:33 into the presentation.
So! Even though you're using Automatic Reference Counting (ARC), it's still a good idea to read up on Objective-C Memory Management:
http://longweekendmobile.com/2011/09/07/objc-automatic-reference-counting-in-xcode-explained/
But, for your specific problem:
Generally, when you see a C method in the Apple frameworks that has the word Copy in it, you're taking ownership of that Core Foundation type and you need to release it. When you want to release that type, just use:
CFRelease(addressFromPerson)
That's the first issue. Your screenshot cuts off the second error so I'm only speculating, but I think you also need to release your NSDictionary *personDictionary. Similarly:
CFRelease(personDictionary)
Note that you also need to manage the memory for linkedPeople
Normally ARC will take care of memory management for you, but when working with Core Foundation types, you still need to clean up after yourself.
I would strongly recommend you check out these great resources on memory management with ARC, particularly when dealing with CF types and toll-free bridging:
http://www.joergjacobsen.com/blog/2011/10/05/managing-toll-free-bridging-in-an-arced-environment/
http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html
Let's say we have some Core Foundation objects, such as CGColorRef, that are added to an NSArray like this:
CGColorRef color = ...;
NSArray *array = [NSArray arrayWithObject:(id)color];
Since arrays retain their contents, color receives a retain message (not CFRetain(), right?). What happens in this case from memory management point of view?
From Core Foundation Design Concepts:
Note from the example that the memory management functions and methods are also interchangeable—you can use CFRelease with a Cocoa object and release and autorelease with a Core Foundation object.
It doesn't specifically mention retain, but, in practice, that works as well, as do copy (various classes' CFFooCreateCopy) and description (CFCopyDescription). The last is how you can pass CF objects as the value for a %# formatting specification when using NSLog and other string-formatting functions and methods.
The result is the same: retain does the same as CFRetain, release does the same as CFRelease, etc.
A few things to be aware of:
Prior to iOS 7 and OS X 10.9, there is no CF counterpart function to NSObject's autorelease method. (7 and 10.9 brought the CFAutorelease function.) If you're not using ARC, then, as mentioned in the documentation quoted above, you can send autorelease to a CF object, and it works the same as on an NSObject.
You can send a message to nil, but you can't call CF functions on NULL (you'll crash). Quartz has some class-specific functions, such as CGContextRetain/Release, that include a NULL check; whether you want to use those or always do your own NULL checks is a matter of style.
CF's retain and release functions work under garbage collection, whereas retain and release messages are no-ops (as if sent to nil). Doesn't matter unless you're working on a GC'd Mac app, in which case you will need to use CFRetain and CFRelease on CF objects.
Similarly, under ARC, retain and release messages will be illegal and CF objects won't be automatically reference-counted. You will need to use CFRetain and CFRelease on CF objects.
Collections always do the right thing, as documented. Usually, this means a strong reference. Outside of GC, that means the collection (array, dictionary, etc.) will retain and release its objects, whether automatically (by assignments, if its code is ARCified) or manually (by explicit retain and release messages).
Is "new" an equivalent of "alloc init" or "alloc init autorelease"?
I cannot seem to find it in any tutorial or article that deals with Cocoa memory management.
Thanks for advise.
How about this one. Read them, understand them, they're simple.
new returns an object with a retain count of 1, just like [[alloc] init]. The object is not autoreleased.
+[NSObject new] is functionally equivalent to +[NSObject alloc] followed by -[NSObject init] (i.e. [[alloc] init]).
To answer your question, from the NSObject class docs:
If you are using managed memory (not
garbage collection), this method
retains the object before returning
it. The returned object is not
autoreleased. The invoker of this
method is responsible for releasing
the returned object, using either
release or autorelease.
Using new is rare in modern Cocoa code. Most Cocoa developers favor explicit, clear code over saving a couple of key strokes. Thus alloc/init is preferred.