views:

279

answers:

3

I am creating an NSDictionary with -initWithObjectsAndKeys:.

For every object I provide to that dictionary I call a selfmade method -createFooBarObject, which will create and return the object.

Now the problem: The create method by definition should not release the object because it must return it, and the caller is responsible for releasing it. But here, the caller has no chance to release it because the NSDictionary sucks it in immediately. I call that create-method right inside the -initWithObjectsAndKeys: list of objects and keys, so I have no chance to call -release after adding to the dictionary. Well I could iterate over the dictionary and release them all. But that's ugly.

So is it valid to -autorelease before returning in the -createFooBarObject method? I'm not sure at which point the -autorelease would take place. But it shouldn't happen before the dictionary was created and retained that object. Any idea?

+4  A: 

If you are calling +alloc to create the object (which you appear to be), then you must release or autorelease.

If you create a method that returns an object that you created with +alloc, then you must return an -autoreleased object.

The alternative is to not do what the design patterns say to do and then deal with your different pattern and the impedance mismatch between. Don't go there unless performance analysis indicates that you have a performance problem that can only be fixed by doing so.

In this case, you would want to return an -autoreleased object. The caller would then not have to worry about calling -release or -autorelease. This is as it should be.

bbum
Further info: http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
Chuck
+2  A: 

For Objective-C APIs, "new" indicates a +1 reference return value. For CoreFoundation, "create" does. The converse is not true: "create" and "new" are not interchangeable.

So in Objective-C, "createFooBarObject" indicates an autoreleased object, according to the current rules, and you should autorelease it. If you really intend to return a +1 reference object, you should use "new" instead of "create" in the name.

These rules are checked by the clang static analyzer.

clang-sa also allows you to specifically annotate methods that you define that differ from the normal conventions via attribute((ns_returns_retained)) or attribute((cf_returns_retained)). For example, there is an edge case if an ObjC method returns a new CF object via "create" (like the QuartzCore -[CIContext createCGImage:fromRect:]). If you have API like this, and clang-sa misinterprets your intention, you can annotate the method to be specific that you do return an object with a particular reference type.

tjw
now I'm confused. I have it from the apple docs that both "create" and new would always have to return a +1 reference where the caller is responsible for releasing. From where do you have that information? Would like to read more about it. Thnaks for the Clang hint, I think that's a really useful thing!
HelloMoon
@IRTFM: I can't find a reference in the memory management docs that say what you're claiming. However, I usually try to avoid restating the memory management rules for just this reason: It's too easy to misstate things and cause confusion, when the canonical list of rules is really easily accessible.
Chuck
The names that return +1 ref for Cocoa objects are listed in docs here http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmObjectOwnership.html#//apple_ref/doc/uid/20000043-BEHDEDDB.
tjw
+1  A: 

Two notes: you create an object with alloc, you init it with initWithObjectsAndKeys - alloc/init is always paired so its only usually a technical difference.

But much more importanly, create methods should NOT return an object that is owned, you should autorelease it. This is explicitly specified in the memory management rules. Given that specification, and the confusion that naming a method "create" causes, I would recommend never use "create" in a method name, instead call it fooBarObject and return an autoreleased (or otherwise unowned) object. If you do that, then your problem immediately solves itself.

So is it valid to -autorelease before returning in the -createFooBarObject method?

It is not only valid, it is absolutely required - if the object you are autoreleasing is owned by you at that point (ie, you could legitimately call release).

I'm not sure at which point the -autorelease would take place.

The autorelease pool is conceptially quite simply - the system keeps a copy of the pointer to your object and when the autorelease pool is drained/released, it sends the release method to the object.

Autorelease pools are nested and will never be magically drained unexpectedly - they will be drained when the flow of control returns back to whoever created the autorelease pool and they release it usually this is the run loop that initially called your code to process an event.

But even this understanding is largely irrelevent - just read the memory management rules and follow those rules and you wont have any problems.

Peter N Lewis