views:

114

answers:

4

hello all,

Whenever I read about how to avoid memory leaks, I always came across a concept that "Number of alloc must be equal to number of release".

But I came across a concept where we require more than one release. Like What I used to practise was as follows:

(NSString*) func1
{
    NSString* result = [[NSString alloc] initWithFormat:@"Test String"]];
    return result;
}

(void) func2
{
    NSString* temp = [self func1];
    [temp release];
}

But I came across a concept of retain count which says that in the above case the memory is not deallocated for the string since the retain count for the string is 1 at the end. So the right practise is

(NSString*) func1
{
    NSString* result = [[NSString alloc] initWithFormat:@"Test String"]];
    [result autorelease];
    return result;
}

(void) func2
{    
    NSString* temp = [self func1];
    [temp release];
}

So now I have two releases for deallocating the memory which is a contradictory to my above sentence which I read on most of the blogs ""Number of alloc must be equal to number of release".

I am little bit confused about the above stuff. Becoz if I autorelease the string in the first function and want to use the string in second function for a long time, and what if the release pool is flushed in between, on the other side if I dont use autorelease it will still block the memory.

So whats the correct way of doing it.

A: 
(NSString*) func1
{
    NSString* result = [[NSString alloc] initWithFormat:@"Test String"]];
    return result;
}

[result retainCount] is 1

(void) func2
{
    NSString* temp = [self func1];
    [temp release];
}

[temp retainCount] is 0

No need for autorelease.

From Memory Management Rules:

This is the fundamental rule:

You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. You are responsible for relinquishing ownership of objects you own using release or autorelease. Any other time you receive an object, you must not release it. The following rules derive from the fundamental rule, or cope with edge cases:

As a corollary of the fundamental rule, if you need to store a received object as a property in an instance variable, you must retain or copy it. (This is not true for weak references, described at “Weak References to Objects,” but these are typically rare.) A received object is normally guaranteed to remain valid within the method it was received in (exceptions include multithreaded applications and some Distributed Objects situations, although you must also take care if you modify the object from which you received the object). That method may also safely return the object to its invoker. Use retain in combination with release or autorelease when needed to prevent an object from being invalidated as a normal side-effect of a message (see “Validity of Shared Objects”).

autorelease just means “send a release message later” (for some definition of later—see “Autorelease Pools”).

mahboudz
It's dangerous to have [retain] and [release] in two separate functions, because it's so easy to leave out a retain or release. You should always return autoreleased objects, unless the method is -copy or +alloc.
Georg
+2  A: 

At the time you call alloc whatever is returned will have a retainCount of 1. Calling release on that object will cause it to be deallocated (it's retainCount will drop to 0). In your first example, then, the second line of func2 will deallocate the NSString* you received from func1, and your memory management chores are complete.

In the second example you are tossing result in func1 into the current autorelease pool, which will cause it to become deallocated when the pool drains. You do not want to attempt to manage the memory of that object once it has been placed into the pool- it is no longer your responsibility.

If you want to generate the string and keep it around for a while (e.g., through the lifetime of several autorelease pools), I would recommend the first form of memory management.

fbrereto
Quite right, except for if you retain something after autoreleasing it it is your duty to release it (or autorelease again) for each time you retain an object. one autorelease won't absolve you of all responsibility :)
Kevlar
Ah, good to know!
fbrereto
+1  A: 

The correct way is this:

(NSString*) func1 {
    NSString* result = [[NSString alloc] initWithFormat:@"Test String"];
    // retaincount == 1
    return [result autorelease];
}

(void) func2 {
    NSString* temp = [self func1];
    // retaincount == 1
    // temp is autoreleased, therefore no [release] is necessary.
}

Autorelease is automatically done at the end of the run loop, that means it cannot be emptied while your code is doing something. -> The code you have is safe. This isn't true for multithreaded application!

Georg
A: 

In general, I'd feel safer to do a retain on a return value, like the one in the "func 2":

(NSString*) func1 {
    NSString* result = [[NSString alloc] initWithFormat:@"Test String"];
    return [result autorelease];
}

(void) func2 {
    NSString* temp = [[self func1] retain];
    // Do something with temp
    [temp release];
}

Is this unnecessary? I understand that in this example "temp" is just a local variable. But it could have been an instance variable, which may need to be retained.

Ushox
Yes it is unnecessary, the autoreleased object will never be deallocated until the end of the current run-loop, or the current NSAutoreleasePool is drained.You are safe unless you explicitly asked to manage your own NSRunLoop or NSAutoreleasePool.
PeyloW