1

New to OC, many years of C, C++, C#, mind is kind of boggled now.

Given:

// AnInterface.h
@interface AnInterface : NSObject  
{  
}  

@property (retain) SomeObject* m_Object;  

// AnInterface.m
#import "AnInterface.h"  

@synthesize m_Object;  

-init
{  
  self= [super init];  
  if(!self)  
    return (nil);  

  SomeObject* pObject= [[SomeObject alloc] init];  
  self.m_Object= pObject;  
  [pObject release];
}  

I am pretty sure the above is correct. However, why not just do:

self.m_Object= [[SomeObject alloc] init];  

Does that work as well? Is it in violation of some memory management tenet? It seems like it should work, one line rather than three, but I am certain I must be missing something....

Any insight would be appreciated.

GTAE86
  • 1,780
  • 3
  • 29
  • 39
  • Very close to duplicates: http://stackoverflow.com/questions/3722998/objective-c-memory-management-question, http://stackoverflow.com/questions/4210700/objective-c-memory-management-question – jscs Aug 10 '11 at 20:11
  • don't call ivars or properties `m_` anything; all that silly gobbledegook notation just isn't used in Objective-C. – bbum Aug 10 '11 at 20:12
  • @Josh - so, according to that post, if I had just assigned the instance directly (m_Object= ...), instead of using the setter, it would work just fine, right? – GTAE86 Aug 10 '11 at 20:25
  • Exactly correct. The issue is with the property access: `self.m_Object`; this goes through a setter method which calls `retain` on the argument. – jscs Aug 10 '11 at 20:29
  • So, why is the three-line model promoted over the more simple, clearer, one-line solution? – GTAE86 Aug 10 '11 at 20:32
  • 1
    There's some disagreement about the use of properties/setters in `init` and `dealloc`; as one example, see: http://stackoverflow.com/questions/192721/why-shouldnt-i-use-objective-c-2-0-accessors-in-init-dealloc. It really comes down to style; Apple's current style is simply to prefer using the dot-syntax property access _everywhere_. I myself like to use the direct ivar assignment in `init`. – jscs Aug 10 '11 at 20:39

3 Answers3

2

The reason is because you defined the property m_Object to retain so it would result in a memory leak because alloc/init call results in a retain of +1 then property will retain giving it at least a retain count of +2. If you would like to make it one line feel free to abuse the auto release pool.

self.m_Object= [[[SomeObject alloc] init] autorelease]; 
Joe
  • 56,979
  • 9
  • 128
  • 135
  • I wondered if it was something like that - thanks. – GTAE86 Aug 10 '11 at 20:14
  • 1
    If you are wondering why I said "abuse the auto release pool" see here http://stackoverflow.com/questions/613583/why-is-autorelease-especially-dangerous-expensive-for-iphone-applications – Joe Aug 10 '11 at 20:15
  • Yeah, I read about that idea in a tutorial. Coming from C and C++, I understand and practice good memory management. However, OC seems to bend over backwards to make it difficult, whereas other languages seem to have made it less onerous over the years. – GTAE86 Aug 10 '11 at 20:21
  • @GTAE86 -- The manual refcount memory management has always caused struggles for new users of Obj-C; [ARC](http://clang.llvm.org/docs/AutomaticReferenceCounting.html) is hopefully the "less onerous" future. – jscs Aug 10 '11 at 20:26
  • Does using garbage collection make any of it easier? – GTAE86 Aug 10 '11 at 20:30
  • @GTAE86: Garbage collection seems to have been a period of brief madness for Apple; I think it was intended to be the future on the desktop, but it's never been available on iOS. It's now all-but-deprecated in favor of ARC. – jscs Aug 10 '11 at 20:41
1

That leaks the object. Since alloc returns an owning reference, and retain claims ownership a second time, you need to call release to balance the alloc or the object will think you want to hold onto it forever and never be deallocated.

Chuck
  • 234,037
  • 30
  • 302
  • 389
1
self.m_Object = [[SomeObject alloc] init];

This causes an over-retain. You get one claim of ownership for the alloc, and another through the setter, which is declared as retaining the new value. Since you only have one pointer to the new value, you have too many claims. When the setter is used again:

self.m_Object = anotherObject; 

the original object will receive only one release message, and you will lose the pointer. Since you had two claims on the object, it will not be deallocated, and you will have a leak.

The property access: self.m_Object = obj; is translated by the compiler into [self setM_Object:obj];. That is, the setter method for the property, created by the @synthesize directive, is called. That setter method retains its argument. The other option is to use the ivar directly in your init method:

-init {
    //...
    m_Object = [[SomeObject alloc] init];
    //...
}

then you have only one claim on this object, caused by the use of alloc. Since you also have one reference to the object, this is correct.

jscs
  • 63,694
  • 13
  • 151
  • 195