views:

318

answers:

1

Hey guys, I'm starting to play around with Objective-C and I want to make sure I get memory/properties right.

Suppose the following code:

@interface Rectangle : NSObject 
{
    Vector2* origin;
    //[...]
}

Rectangle* myRect  = [[Rectangle alloc] init];
myRect.origin.x = 100.0f;
[myRect print];
myRect.origin = [[Vector2 alloc] init]; //hummm.. 2 concerns here.

Concern 1:

Suppose origin is a standard (assign) synthesized property:

Does myRect's previous origin ref count goes to 0 automatically when assigning the new Vector2 and GC will take care of it later on? Or I have to call release explicitly inside the property?

Concern 2:

Suppose origin would be a 'retain' property: (BTW: Would that kind of code be automatically generated when declaring a synthesized retain property, is that possible?)

-(void) setOrigin: (Vector2*)newOrigin {
   [newOrigin retain];
   [origin release]
   origin = newOrigin;
}

Then when doing:

myRect.origin = [[Vector2 alloc] init]

Wouldn't that cause a double ref count increment and then needing release to be called twice to avoid leak? Do you guys rely on well-documented code (to know it's a retain property) when using libraries/other people's code to avoid such problems, or is there some safer ways of alloc/init objects?

Thanks for tips!

+4  A: 

Concern 1:
[...] Does myRect's previous origin ref count goes to 0 automatically

No, an assign property does just what it says - assign. It doesn't retain nor release - you have to handle that manually in that case.

Concern 2:

myRect.origin = [[Vector2 alloc] init]

Wouldn't that cause a double ref count increment

Yes, thats why you'd either use autorelease:

myRect.origin = [[[Vector2 alloc] init] autorelease];

... or manually release it:

Vector2 *v = [[Vector2 alloc] init];
myRect.origin = v;
[v release];

As for how to manage those problems:

  • read the memory management guide
  • look what the documentation or the property declaration says
  • for parameters passed to methods always assume the callee retains if needed - unless documented otherwise
Georg Fritzsche
This answer assumes that `origin` is of object type. If it isn't, the question and this answer don't makes any sense at all for reasons that are subtle and unfortunate. If it is, then happy day... Georg beat me to it.
bbum
Right. Since you alloc'd or retained the vector2, then you have to release it. Giving it like this to the myRect will cause the myRect to also retain it. (And then myRect will in turn be responsible for also releasing it when its done with it.)
Mike Kale
+1 for the link to Cocoa Memory Management
JeremyP
Ok, therefore most setters receiving a NSObject* (or derived) as a parameter will mostly be retain properties, since an assign would be a bit... risky.What about @property (retain) someVar with a @synthesize afterwards.Would that automatically generate the retain/release old/assign code or you have to implement each retain properties?Thanks!
turbovince
@turbo: There are important cases where retain properties don't make sense - see [weak references](http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/MemoryMgmt/Articles/mmObjectOwnership.html#//apple_ref/doc/uid/20000043-1044135-BCICCFAE) and [Core Foundation](http://developer.apple.com/mac/library/documentation/cocoa/conceptual/objectivec/Articles/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW10).
Georg Fritzsche
As for `@synthesize`, it will generate you the retaining/releasing setters, see e.g. [here](http://developer.apple.com/mac/library/documentation/cocoa/conceptual/objectivec/Articles/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW27).
Georg Fritzsche