views:

63

answers:

3

Hi,

I had a look at instruments and I saw that the alloc increased the retain count by 1. So far everything clear. But the assignment of the class to my property also increased the retain count to 2.

self.myProperty = [[MyClass alloc] init]

Vs.

MyClass *myCreatedVariable = [[MyClass alloc] init];
self.myProperty = myCreatedVariable

To decrease the retain count to zero I released myCreatedVariable right after my calls. The myProperty instance variable is released in the dealloc method. Am I right that a property only is released in the dealloc method?

Now to my question:

Is the allocation and the assignment to a property always creating a retain count of 2? So don't use

self.myProperty = [[MyClass alloc] init]

because the retain count is never getting zero? Or is this only the case if I'm allocating a class?

Cheers

+4  A: 

Your property is most probably declared as retaining or copying:

@property (retain) MyClass myProperty;

or

@property (copy) MyClass myProperty;

This calls your setter that does what its attributes say: retain! Copy will also retain.

Although it worked here, you shouldn't try to get useful information out of the retainCount property.

I cannot recommend the Memory Management Programming Guide highly enough, well worth a first, second and third read. :-)

Eiko
`copy` does *not* `retain`. `copy` *usually* results in the creation of a new (owned) object. It's possible that the class may override the `copy` method to simply do `return [self retain];`, but that is an implementation detail.
Dave DeLong
OK, the answer is to "Is the allocation and the assignment to a property always creating a retain count of 2?" is no, because of the defined retain property. I'll have another look at the MMPG, but before I forget: What would be if I do not retain the property? (=Why I'm retaining my property?) How to release a retained and allocated property? Either use autorelease or do something like [myProperty release]; [myProperty release];?
testing
@Dave DeLong: Well, copy might not retain - and indeed it may just retain itself for immutable objects. But no matter how it is implemented, be it alloc or retain, for memory management consideration it is the same. This was my point here, as we actually didn't know how the property was specified.
Eiko
@testing: If you do *not* give the retain attribute in your property declaration (and don't implement it otherwise which I'd consider a bug), then it would be just *assign*ed. You can get along with many implementations and you can code against the conventions. In general, this results to code that is hard to understand, and often either leaks (because of over-retaining) or crashes (over-releasing). Re: using the retained property: Either release it after setting, or use autorelease - release has the (very slight) edge performance/memory wise.
Eiko
@Eiko I understand your point; my comment was just clarifying your sentence that "Copy will also retain", which is usually incorrect.
Dave DeLong
@Eiko: So I do not have to use a retained property, if I'm using an alloc. But it is against the convention. The release thing: If I use self.myProperty = [[MyClass alloc] init] I have to release it twice (if I not use autorelease)?
testing
You have to release it once - either with *release* or *autorelease*. And of course, in your dealloc method *release* it as well.
Eiko
I had the problem with my XML parser. If an error occurred, the dealloc method was not (properly) called. I searched the memory leak with instruments and since I'm releasing it twice in parseErrorOccurred, I have no memory leak anymore. (The property was set in connectionDidFinishLoading:) Perhaps I'm still doing something wrong.
testing
A: 

Creating objects using the init function returns a retained instance by default. ( See the Memory Management Programming Guide)

If the property is defined with the 'retain' attribute, then your object is retained one more time.

So the right way to do is

MyClass *myCreatedVariable = [[MyClass alloc] init];
self.myProperty = myCreatedVariable;
[myCreatedVariable release];

By the way this is good to know also when you using Arrays. Once an object created with the alloc and init functions is added into an array, it is retained by the array, so you can release your instance after you add it in the array.

In both case, retainCount is then 1, as expected.

if your property is defined with the 'copy' attribute, you can release the object as well, and even kill it, since it has been fully copied and retained once. ( I think there is something there if you use garbage collection instead of managed memory... To check.. )

Finally if your property is set with the 'assign' attribute, only the object's adress is copied, so you should not release your original object in this case.

It is however not recommanded to use the 'assign' attribute, since you may set property with objects that you did not create yourself, and which could be released anytime, letting your property pointing in the fields...

Finally, don't forget that static creators in Cocoa do not return retained objects. ( This is a convention, exceptions may exist... )

example:

NSArray* myArray = [NSArray array];
self.myProperty = myArray;

In this case, do not release myArray, it is already done in the creator function. Assigning it to the property will retain it.( with retain or copy attribute).

Hope it will help,

Cheers

Tristan Leblanc
Thanks for your wrap up. I've already done it like in your first code snippet. So if I use addObject: for my NSMutableArray I can release it right after the add. Good to know (I looked into my code and I've done it already as you said, without knowing it really). And in the second code snippet I never did an alloc/retain/... so I don't have to release it. OK, everything clear. Sorry for my nescience: But what is a static creator? To "init function returns a retained instance by default": The problem was not the init function, the problem is the alloc and the retained property.
testing
A: 

Hi,

Sorry ? Noooo. I'm afraid programming is trying to know things we don't know everyday !

Static creators are convenience function, to ease common objects allocations. A lot of classes in the cocoa framework have this kind of functions. Arrays, Dictionary, Paths, ...

Let's take your class as an example, and suppose you often have to create objects of this class. You may write a function in your 'myClass' implementation like:

+(MyClass*)myClass
{
  MyClass *myNewInstance = [[myNewInstance alloc] init];
  return [myNewInstance autorelease];
}

Then you can rewrite your original example as:

..
self.myProperty = [MyClass myClass];
..

Straight! Or you could write a method like

-(void)myFunction
{
  MyClass* myTempObject = [MyClass myClass];
  if (myTempObject) {
    // do something with your temporary object
  }
  // Simply exit, object will be released later on.
}

It is much shorter ( we should handle the case where object creation failed ) ..

Note that this is all conventions, you can basically do has you like and create retained objects, or use a different name for the creator. But it is safer to follow the framework rule, it then becomes a reflex when you code. See methods like [NSDictionary dictionary], [NSArray array], [NSArray arrayWithObjects:] ,...

Cheers

Tristan Leblanc
Many thanks for the education! Very easy to understand!
testing