views:

51

answers:

3

I know this has been discussed ad-nauseum but I just don't get some of the memory management. I understand that retain keeps the object alive and copy gives one a separate copy of an object.

What I don't get is when it comes to ivars & properties, retain as a property means that the setter releases the old value & retains the new:

property = newValue;
// retain
if (property != newValue)
{
   [property release];
    property = [newValue retain];
}

but I've seen examples where they assign static strings to the retain property ivars e.g.

self.stringProperty = @"something";
(some other code)
self.stringProperty = @"somethingElse";

The second call to set string should call release on the static string which is not allowed, why doesn't the program crash?

Also, if an object is declared with the retain property & then is assigned something with init, e.g.

@property(retain)someArray;

someArray = [[NSArray alloc] initWithArray:arbArray];

does that mean someArray now has a retain count of 2 but if it was created with

someArray = [NSArray arrayWithArray:arbArray];

the retain count is only 1 because the 2nd is a factory method?

+3  A: 

The second call to set string should call release on the static string which is not allowed, why doesn't the program crash?

You can pass release to a constant string, it just won't do anything meaningful, so those lines of code are valid.

does that mean someArray now has a retain count of 2 but if it was created with...the retain count is only 1 because the 2nd is a factory method?

Well, first of all,

someArray = [[NSArray alloc] initWithArray:arbArray];

doesn't use the methods created by @property, it just accesses the ivar directly. To use the property methods, you'd have to use self.someArray = ...;.

But yes,

[[NSArray alloc] initWithArray:arbArray]

returns an object with an effective retain count of 1, and

[NSArray arrayWithArray:arbArray]

returns an object with an effective retain count of 0, so if you did pass them through the "retain" setter created by @property, the ivar would have an effective retain count of 2 and 1, respectively.

mipadi
Thank you. I can't remember all 5 C's of good communication but your answer fulfilled the 3 that I can remember: clear, concise, correct.
Spider-Paddy
A: 

This is more that one question, but anyway...

Static strings are special cases in a number of ways, one of which is that you can retain and release them to your heart's content without it having any effect.

As an aside, NString properties often have copy rather than retain semantics, which would anyway obviate that question if it mattered. But it doesn't.

In your second case, assigning to a retain property directly from an alloc (or copy or other ownership-granting call) is bad practice and will leak unless you actively add a corresponding release afterwards, or autorelease during, eg:

self.someArray = [[[NSArray alloc] initWithArray:arbArray] autorelease];

But there's really no reason not to use the class method in this particular case.

walkytalky
The 2nd part about the retain counts was my actual question, the first bit was just something that was bothering me but I will separate questions in future. Thanks for the response.
Spider-Paddy
A: 

The second call to set string should call release on the static string which is not allowed, why doesn't the program crash?

It's not a static string, it's a constant string. However, that is irrelevant to the question, but actually you are allowed to send -retain to any Objective-C object derived from NSObject except NSAutoreleasePool. If you look at the retainCount (a bit naughty, but since we are discussing implementation, OK) of a constant NSString e.g.

NSLog(@"retain count = %u", [@"foo" retainCount]);

you'll most likely find it's set to a really big number (UINT_MAX in fact). This is a signal to the run time to ignore calls to release and retain.

By the way, forgetting to release objects won't crash the program straight away. In fact, if you have lots of RAM, you might not notice until the OS starts swapping.

does that mean someArray now has a retain count of 2 but if it was created with

No, because you didn't use the property to assign the new array, you went straight to the ivar:

self.someArray = [[NSArray alloc] initWithArray:arbArray];

would be a leak.

self.someArray = [NSArray arrayWithArray:arbArray];

would be OK.

JeremyP