views:

158

answers:

4

In the book I'm studying from for iPhone dev, they utilize IBOutlet instances using the Interface Builder. An example would be a UIButton. So they add a thing in the struct like this:

 IBOutlet UIButton *whateverButton;

Then they add a @property for each of these in the .h, and a @synthesize in the .m.

Then they include a release in the dealloc of the .m. Two questions:

  1. Is the release necessary? Aren't all properties already handled automatically?
  2. How can I check the ref count to see what's happening, for debug purposes...?
+5  A: 

Properties are not "handled automatically." The closest that comes to being true is that synthesized accessors handle their memory management responsibilities properly. But that is just those accessors. Properties are just a way of declaring accessible "things" on your class. They don't get much special treatment beyond that. It doesn't turn on some sort of garbage collection. So yes, release is necessary.

And you should use the debugging tools like Instruments if you want to inspect a running app for leaks or memory that doesn't get released. I would not look at the ref count directly, because it's almost dangerously useless — there's no guarantee that the ref count will be what you expect at any point, and that doesn't necessarily indicate a problem.

You should read Apple's memory management rules for Cocoa. It's pretty simple once you've absorbed that. I wouldn't necessarily recommend reading other guides first, because subtle misstatements can lead you down the wrong path (for instance, the idea that properties will be released for you probably came from hearing somebody misstate how they work).

Chuck
Thanks Chuck, that helps. I got that idea somewhere here on SO, but I'm sure/I hope I'm misquoting or I've misunderstood.
Yar
Yeah I see it now, I thought that the setter doing it's retain/release correctly was somehow "some sort of garbage collection." It's just saving me the work from doing the retain/releasing in the setter.
Yar
+3  A: 

Is the release necessary? Aren't all properties already handled automatically?

It depends on how the property is implemented. If it is auto-implemented (@synthesize'd), the property will retain its value in the setter and release it if set to another value. If you just got into Obj-C and Cocoa, you should read about the conventions for memory management. I have put up a post on my blog about them, there are plenty of resources elsewhere too.

How can I check the ref count to see what's happening, for debug purposes...?

You can check the NSObject retainCount property. Information on that is here. For advanced debugging purposes, there is the NSZombieEnabled environment flag that will cause all release message to not decrement the reference count but log an error when an object that would have normally been released is accessed.

Johannes Rudolph
It doesn't depend on how the property is implemented. If it's a retain property, you must release it in dealloc.
Chuck
thanks for that. So I guess I was confusing the setter (they call it a monger? can't remember) being set up correctly with not needing to call the retain explicitly. I see my error now.
Yar
@chuck: what about weak references?
Johannes Rudolph
@Johannes: If you're talking about `__weak`, it has no effect in a non-garbage-collected app. Though it usually makes sense for a weak reference to be an `assign` property, in which case you don't need to release it (since you don't retain it).
Chuck
I was talking about assign. I could have been more precice about this and dealloc release(i've seen dealloc implemented by means of setting the property to nil too, didnt want to confuse anyone. ) Good point though.
Johannes Rudolph
+4  A: 

Is the release necessary? Aren't all properties already handled automatically?

If the property is retained, the release is necessary. When you declare a @property and @synthesize it, all you get is the accessors, there is no special automatic behaviour in dealloc.

Also, there is nothing magical about IBOutlet – it’s just a marker for Interface Builder to see which properties you would like to appear in IB. It’s simply an empty macro, Cmd-click the IBOutlet keyword to see its definition:

#ifndef IBOutlet
#define IBOutlet
#endif

Same thing goes for IBAction which expands to void.

How can I check the ref count to see what's happening, for debug purposes...?

When I need to debug memory management, I usually simply set up a breakpoint in the dealloc method or log a string there. It is also helpful to log the retainCount of an object around the calls that might do something fishy with it.


It might also help to see how the @synthesize directive creates the accessors. When you declare a retained @property and ask the compiler to @synthesize them, you get something like this:

@property(retain) NSString *foo;
@synthesize foo;

- (void) foo {
    return foo;
}

- (void) setFoo: (NSString*) newFoo {
    // Try to think what would happen if this condition wasn’t
    // here and somebody called [anObject setFoo:anObject.foo].
    if (newFoo == foo)
        return;
    [foo release];
    foo = [newFoo retain];
}

This isn’t exactly the thing, but it’s close enough. Now it should be more clear why you should release in dealloc.

zoul
Excellent notes on everything, especially the stuff on IBOutlet that I might never have learned. Thank you.
Yar
Several people on SO have told me that logging `retainCount` is unreliable. (I've not tried it myself.) Obligatory link to The Rules: http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH
andyvn22
I’ve never had any problems with it. But giving it a second thought, I did not log it in the dealloc, I’ve always logged it around some other calls. (I’ll update the answer.)
zoul
+1  A: 

(1) release is absolutely necessary. if you use "retain" in the @property statement you must release it. That's that.

(2) IBOutlet is completely irrelevant, it's just a marker within the XCode milieu that helps interface builder work properly.

(3) In your question 2 you're thinking of retainCount, try it but it's almost useless. Also try using "Run with performance tool -> Leaks" or whatever. Also perhaps a little useless! But might as well try it.

(4) A related issue that may possibly help you. It's well worth remembering that self.yourProperty = something is wildly different from yourProperty = something. Don't mix the two up and try to delve into understanding the distinction as deeply as humanly possible! Hope it helps!

Joe Blow
Thanks. This question seems easy to me (now), but this answer would've helped at the time.
Yar