开发者

Objective C - Memory Management Question?

I know that when setting a retained property to an allocated object it increments the retain count of the object so i need to release it (3rd line, first block of code)

But what if i don't have a property, and I am assigning an allocated object to an instant variable. Do i still need to release it????? (3rd line, second block of code)

@property (nonatomic, retain) MyObject *myObject;

MyObject *obj = [[MyObject alloc] init];
self.myObject = obj;
[obj release];

开发者_运维百科
MyObject *myObject;

MyObject *obj = [[MyObject alloc] init];
myObject = obj;
[obj release];

PLEASE read the full details before marking as duplicate


I know that when setting a retained property to an allocated object it increments the retain count of the object so i need to release it (3rd line, first block of code)

No, you don't know that. For instance

foo = [[NSString alloc] initWithString: @"foo"];
[self setMyProperty: foo];

will not increment the retain count which will start off as INT_MAX and stay there. However, these are all implementation details and should not be thought about. You should really be thinking in terms of ownership and when you want to relinquish ownership.

In your first code block, the variable obj will go out of scope once the block it is in has been exited. The reason you need to send release to it has nothing to do with the fact that you have assigned it to a property and everything to do with the fact that you are no longer interested in an object that you own (because the pointer to it is about to go out of scope). By "you" incidentally, we mean the scope in which the pointer exists.

In the second case, you are assigning the object to an instance variables. Instance variables live as long as the object they are an instance variable of. Thus you need to own it until either the object is deallocated or the instance variable is changed to point to a different object.


I will assume that in both your examples the line standing on it's own is the property and the instance variable as defined in the class interface. And that the other code is executed from some method in that same class.

Lets look at what happens:

@property (nonatomic, retain) MyObject *myObject;

MyObject *obj = [[MyObject alloc] init];  // Retain count = 1
self.myObject = obj;         // Retain count +1 (2), because property is defined
                             // as retain.
[obj release];               // Retain count -1

In this example everything works as it should. Lets look at the second one:

MyObject *myObject;

MyObject *obj = [[MyObject alloc] init];  // Retain count = 1
myObject = obj;              // Retain count still 1. Assigns never changes
                             // retain counts.
[obj release];               // Retain count -1 (0), object is now deallocated.
                             // Any access to it though obj or myObject WILL
                             // cause a crash.

You can actually code Objective-C and treat it as almost 100% garbage collected, you just need to trust the auto release pools. Whenever you allocate an object you should also immediately hand it over to the auto release pool. That way you only need to worry about retaining what you want to survive past the end of the current method.

Your first example could be:

@property (nonatomic, retain) MyObject *myObject;

MyObject *obj = [[[MyObject alloc] init] autorelease];
self.myObject = obj;        // Implicitly retain through property

And your second would be:

MyObject *myObject;

MyObject *obj = [[[MyObject alloc] init] autorelease];
myObject = [obj retain];    // Explicitly retained to survive end of method

As you can see simply adding autorelease when allocating new objects, and consistently using properties will reduce memory management to just releasing instance variables in the dealloc method.


In your second example both obj and myObject have been dealloc'd after you call -release since the retain count goes from 1 to zero. In the first example, since your @property has "retain", the retain count goes from 1, to 2, then back to 1 when you release it, so it is not dealloc'd.

In short, you should not release objects you directly assign to ivars, except from within your -dealloc method, or before assigning something else to the same ivar.


In your second example, you could remove the redundant variable obj and it would look like this:

MyObject *myObject; // declared as instance variable

//---//

myObject = [[MyObject alloc] init];
[myObject release];

You can see straight away that myObject is deallocated immediately, because you have balanced your alloc with release.

When assigning directly to instance variables, you:

  1. Generally do not need to use temporary/intermediate/auxiliary variables, especially for simple cases like the above.
  2. Do not release it after assigning it.
  3. Generally, ensure that the instance variable is not autoreleased (for example, do not use the convenience class methods, like stringWithFormat: and instead use the alloc + initWithFormat:, or, if you do use a convenience class method, make sure you explicitly retain).
  4. As with properties, ensure that you release it in your class's dealloc method.


Expanding on @PeyloW's answer (which is 100% correct and should not have been down-voted)...

There are special circumstances which result in discouraging use of accessors in -init and -dealloc. (Primarily key-value observing, but also overridden accessors that may have consequences/side effects that are not appropriate for a partially initialized or partially deallocated object)

Therefore, your -init method should probably be something like:

//@property (nonatomic, retain) MyObject * myObject;

- (id) init {
  self = [super init];
  if (self) {
    myObject = [[MyObject alloc] init];
  }
  return self;
}

- (void) dealloc {
  [myObject release];
  [super dealloc];
}

And then everywhere else you would use [self setMyObject:] and [self myObject] (or self.myObject, if that's how you roll)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜