views:

616

answers:

4

Currently I am jumping into the ice cold water called "memory management in iPhone OS".

Here's one rule i've learned:

Every time I see an alloc in my method, I will release that corresponding variable at the bottom of the method.

Every time I create an @property(...) in my header file which says copy or retain, I put a release message on that variable into the dealloc method.

Every time I have an IBOutlet, I do the same thing. Only exception: If the IBOutlet has something like @property(... assign), or in other words: If it has the assign keyword at all. Then I don't care about releasing it in the dealloc method.

I feel that there are many more good rules to know! Just write down what you have. Let's scrape them all together. Links to great descriptions are welcome, too.

+3  A: 

Actually, any time you initialize an object and the method name includes "init" you are responsible for releasing it. If you create an object using a Class method that does not include the word "init" then you don't.

For example:

  NSString *person = [NSString stringWithFormat:"My name is %@", name];

does not need a release. But:

  Person *person = [[Person alloc] init];

needs a release (as you stated in your question). Likewise:

  Person *person = [[Person alloc] initWithName:@"Matt"]];

also needs a release.

This is a convention, not a rule of the language, but you will find that it is true for all Apple-supplied APIs.

mmc
Your third example shouldn't even exist: Initialization methods shouldn't be static, so they should be called on an object already allocated with alloc. Yes, this is only by convention, but it's convention for a good reason. Static methods return auto-released objects, alloc-init returns a retained object.
Tony
@Tony: It looks like a typo in the third example, because the brackets don't match. When is a method a static method? How do I see that without an static keyword (like in Java, i.e.)?
Thanks
Both of you are right, I grossly typoed that third example. That's what I get for typing from memory in a web browser. Fixing it.
mmc
@mmc: Is the first example also valid for NSString *str = [NSString stringWithFormat:"My name is %@", name]; (If I assign that to an NSString variable)?
Thanks
yes it is, and I'm glad that we're thinking along the same lines. I edited the first example to be more clear as you were typing your comment :)I'm having a really bad code day, even at work debugging an aspx error page... maybe I should not answer any more questions today :)
mmc
Although I am not sure about my knowledge yet (just started with Objective-C and iPhone SDK), I am pretty sure about the correctness of this examples here. Have a big book here that says the same thing (looked it up yesterday evening).
Thanks
Not true, the init has nothing to do with it. This should be written as, "Anytime you call alloc, you need to worry about freeing the memory."
rik.the.vik
+1  A: 

I tend to create only autoreleased objects, either by using a class method or by autoreleasing it immediately after creation, unless I can state a reason not to. For example:

  • I am assigning it to a member variable because I intend to hold onto it for a while.
  • I am only creating it to pass it on immediately to another method, and I send it a release message right after that method call.
  • For performance reasons, I need to free that memory before the nearest NSAutoreleasePool will be released, such as creating a large number of objects inside a loop or the objects are holding onto a large amount of data (e.g., images).

That way, I am less likely to leak objects. By default, I create them autoreleased, and when I make the deliberate decision not to autorelease them, I am immediately faced with the question of where they will be released.

For object properties, rather than releasing them in my dealloc method, I like to assign nil to them. That way, retained or copied properties are sent a release, while assigned properties are simply overwritten, and I don't have to update my dealloc method if I change the property to/from retained.

Tony
Assigning nil in dealloc (instead of calling release) is frowned upon, since something could break if another object is registered for KVO notifications, or you write a custom setter method that tries to use another instance variable (which may have already been wiped out).
Marc Charbonneau
I used to do this, but I eventually decided that having massive numbers of objects in the autorelease pool made it difficult to figure out what was going on. Now I use alooc/init and release everywhere, except when it can't be helped.
Mark Bessey
@Marc: I hadn't considered that, thanks for pointing that out. I suppose that deserves its own point in memory management: Avoid side effects in your destructor (dealloc method).
Tony
+2  A: 

Memory management can seem daunting when you're seeing segfaults spring from every seeming innocent line of code, but it's actually pretty easy once you get the hang of it. Spend a little time reading this page and then Apple's documentation, and you should be writing bug-free code in no time.

Marc Charbonneau
+3  A: 

The rules I use

  • Release all objects you create using a method whose name begins "alloc" or "new" or contains "copy".

  • Release all objects you retain.

  • Do not release objects created using a +className convenience constructor. (The class creates it and is responsible for releasing it.)

  • Do not release objects you receive in other ways E.g. mySprockets = [widget sprockets];

  • If you store an object you receive in an instance variable, retain it or copy it. (Unless it's a weak reference - just a pointer to another object, usually to avoid cyclical references.)

  • Received objects are valid within the method they are received in (generally) and are also valid if passed back to the invoker.

Some good links:

  1. http://www.gehacktes.net/2009/02/iphone-programming-part-2-objective-c-memory-management/
  2. http://mauvilasoftware.com/iphone_software_development/2008/01/iphone-memory-management-a-bri.html
Jane Sales