views:

201

answers:

4

Plenty of Objective-C classes return objects. Statements like [[instanceOfNSWhatever objectForKey:aKey] stringValue], for instance, appear all over my (and hopefully everyone else's code).

How am I supposed to memory manage these "intermediate" objects?

  • Were they just created or did they always exist?
  • Can I retain them, and if I release the object that created them, will they be released as well?
  • Are they autoreleased?
  • What if I run [instanceOfNSWhatever stringValue] a million times in a loop? Can I dispose of all those NSStrings as needed?

I'm still learning ObjC, and while I've been good at balancing my retain counts overall, I'm definitely lacking some understanding about how these methods work. Can anyone fill me in?

+5  A: 

You basically manage all your memory according to the Memory Management Programming Guide for Cocoa. In short, however, you basically only need to worry about objects that you "own". You own an object if you create it (in Cocoa, you create an object by specifically allocating it using alloc or copying it using copy or one of their derivatives). If you own an object, you are responsible for releasing it when you are finished with it.

Any other object is, therefore, not owned by you. If you need to use such an object for any extended period (for example, outside the scope in which you received it), you need to specifically take ownership of the object by either sending it a retain message or copying it.

To answer your last question, if you are creating a lot of temporary objects in a loop or some other way, you can create your own autorelease pools. See the documentation for NSAutoreleasePool for more information about using them. Please note, however, that you should really only do this after you've profiled your application and found that it is using too much memory and would benefit from this kind of optimization.

Finally, if you are creating and releasing a lot of heavy objects and don't want to rely on autorelease pools, you can specifically allocate and initialize them and then make sure to release them on your own as soon as you're finished with them. Most objects that have convenience creators have similar initializers for creating the object specifically.

Jason Coco
+1  A: 

I'll tell you a simple rules I wish I'd known when I first started Objective-C :)

  • If an method contains the words "alloc" or "copy" then you must [release] the object when finished.
  • If a method does not contain these words, you must [retain] it for it to remain valid outside of your function.
  • If you call [retain] you must later call [release] when finished.

This covers practically all you need to know about the basics of memory management.

ObjC makes heavy use of what are known as "auto release" pools. Objects returned from non alloc/copy functions are placed into these pools and automatically freed after your function exists.

That is why you do not need to release the results of something like [obj stringValue].

Andrew Grant
+7  A: 

You've probably already read this section of Apple's docs about memory management, but I'll point you to the section about the Object Ownership Policy just in case. You are only responsible for managing the memory of objects you "own". To quote the docs:

  • You own any object you create.
  • You "create" an object using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy).
  • If you own an object, you are responsible for relinquishing ownership when you have finished with it. [ie: release]
  • If you do not own an object, you must not release it.

The "Simple Examples" section of those docs provide good elaboration, but to put the points above in the context of your specific questions:

How am I supposed to memory manage these "intermediate" objects?

The good news is: you don't. Ignore the the memory management aspect of the "intermediate" objects in your example.

  • Were they just created or did they always exist?

They may have always existed, or they may have just been created. The beauty of objective-c is that you, as a consumer of those objects, don't have to care.

  • Can I retain them, and if I release the object that created them, will they be released as well?

You don't need to retain them if you're just passing them on to some other function, or using them as intermediate values yourself in your own calculations within the function. Say, for example, that you're returning the stringValue from your example function to someone else. There's no point in retaining it just to return it.

If you DO happen to retain it, then yes, you are responsible for issuing a corresponding release message as some point. You might, for example, retain the stringValue from your example if you want to hold on to that value as a property in your own instance. Objective-C uses reference counting. If you need that object to stick around for a long time, you must retain it so that someone else's release message doesn't cause it to vanish if the retain count falls to 0.

Are they autoreleased?

Depends. Let's say you ask for a string from instanceOfNSWhatever. If instanceOfNSWhatever has to create that string just special for you (in order to service your request), but doesn't otherwise care about that string, then yes... instanceOfNSWhatever probably put that string into the autorelease pool. If the string was already a property of instanceOfNSWhatever and it was just sending it to you in response to your request, then no, it probably wasn't autoreleased.

Again, the beauty is: you don't know and don't need to care. Since instanceOfNSWhatever created the string, it is responsible for managing it. You can ignore the memory management unless you add to the string by sending it a retain message.

What if I run [instanceOfNSWhatever stringValue] a million times in a loop? Can I dispose of all those NSStrings as needed?

No need. Again... stringValue isn't yours to manage because you didn't create it. As a technical note, if instanceOfNSWhatever really did have to create 1 million copies of stringValue to service your 1 million calls, it probably put them all in an autorelease pool, which would be drained at the end of the current cocoa event loop. Fortunately, unless you send each of those stringValue objects a retain message, you can gleefully ignore the memory management question here.

Jarret Hardie
Good answer. I'd upvote you twice if I could.
Abizern
Appreciate the kind words. Thanks!
Jarret Hardie
Oh, I really like your answer too! +1
Jason Coco
+2  A: 

When working on the iPhone/iPod Touch, the autorelease objects are released when your application exits. This may be what you don't want. Especially when working with images or large chunks of data. To insure large pools of memory that are tagged autorelease get released sooner, create local autorelease pools. Like this:

NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init];

-- do something that creates large autorelease memory blocks --

[localPool drain];

If you don't do this, you will find your application exiting unexpectedly.

Sophtware
Are you sure about this? By nature, everything is released when an application exits. Aren't autoreleased objects released at the end of every event loop?
Sidnicious