Is this the right way to use NSAutoreleasePool? - objective-c

I'm new to Objective-C and I'm not sure if I'm using NSAutoreleasePool the right way.
If I want to use autorelease only one time I use:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *newText = [NSString stringWithFormat:#"%d", prograssAsInt];
sliderLabel.text = newText;
[pool release]; //newText will be released
If I want to use autorelease several times I use:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *newText = [NSString stringWithFormat:#"%d", prograssAsInt];
sliderLabel.text = newText;
[pool drain]; //newText will be released
newText = [NSString stringWithFormat:#"%d", prograssAsInt];
sliderLabel.text = newText;
[pool drain]; //newText will be released
newText = [NSString stringWithFormat:#"%d", prograssAsInt];
sliderLabel.text = newText;
[pool release]; //newText will be released
Is this OK? Are there any memory leaks?

(2) is not OK. -drain and -release are equivalent (in a ref-counting environment), and aftering -draining the autorelease pool is deallocated. So you will double-release the autorelease pool object and crash the program.
Even before ARC, unless you are working in a very tight memory budget, it's atypical to create an NSAutoreleasePool besides the boilerplate main(). The objects -autoreleased into the pool will be released after every tick of NSRunLoop anyway. There will be no memory leak if you strictly follow the ownership transfer rules (see Understanding reference counting with Cocoa and Objective-C).
And with ARC turned on you don't even need to care about this — the compiler will insert the -retain and -release at the right place for you.
Also, if sliderLabel.text is marked as #property(retain) (or (strong)), then releasing the autorelease pool in (1) will not release the newText because that object has a new owner now.

I would say the calls to [pool drain] are unnecessary. I've never seen them used in practice. I suppose if you are allocating huge amounts of memory inside the autorelease pool, it might be necessary. But in the typical case, I would think not.
You will want to start using the following construct, by the way, for autorelease pools:
#autoreleasepool {
... your code ...
}
This is, apparently, much more efficient than the "old" way (the way you are doing it). Functionally, it's the same, but internally it performs much better. There was something about this in recent Xcode/iOS release notes.

Sorry to say this, but RTFM. After -drain is called, the pool deallocates itself, so that it is invalid.
And, currently, in objective-c with Apple's LLVM compiler, there is a language addition called #autoreleasepool that works with both ARC and non-ARC code, that you can leverage as such:
#autoreleasepool {
// code that will automatically have any -autoreleased variables cleaned up.
}

Normally, if you're on the main thread and you're not using a huge loop of resource intensive code, you don't ever need to create your own autorelease pools. Just use the default one that's created for you.
You only need to make your own if you're multithreading or if you're doing a memory intensive long-running loop (which you probably shouldn't do on the main thread anyway).

Related

the autorelease of an object in a ObjC program

Here we have some examples from About Memory Management
In the first example
- (NSString *) fullName {
NSString *string = [[[NSString alloc] initWithFormat:#"%# %#", self.firstName, self.lastName] autorelease];
return string;
}
In this example is how the above method is called
{
Person *aPerson = [[Person alloc] init];
NSString *name = aPerson.fullName;
[aPerson release];
}
So I assume that the *name is autoreleased after code flow reaches the closing curly braces.
Is that true?
And in general autorelease of an object, depends on the scope and lifetime of the variable which references that object.
Are there any criteria which manage the autorelease pool of objects in a Objective-C program?
Thanks.
Release of an autoreleased object takes place when the autorelease pool which the object has been pushed to by autorelease is released/drained explicitly, provided that the object's retain count at that moment is 0+ (that is, nobody else but the autorelease pool is retaining it).
An object is not getting autoreleased just because it has gone out of scope. In your example we can only say for sure that it won't get released before the closing curly brace, but as H2CO3 said, without the relevant source code we cannot predict when it is actually cleaned up. In Cocoa (Touch) apps, threads with runloops have a loop-level autorelease pool which they drain at the end of each runloop iteration. If your method is called from the runloop (e.g. as part of an event handler callback), autoreleased objects will be released shortly after the handler code returns; otherwise there is no such guarantee.
Note that the above holds for non-ARC environment; others may confirm whether it's still valid or not when using ARC.

Objective-c memory management

As a new comer to Objective-c and its memory management technique, comparing two pieces below. (the original code was exacted from apple.com autorelease pools)
Questions:
1. Do the two pieces achieve the same result?
2. Do the two pieces achieve the same memory management result? ( as far memory cleaning up, leaking, etc.)
3. Does the 2nd code below violate anything as far as best practices? Performance?
void main()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *args = [[NSProcessInfo processInfo] arguments];
for (NSString *fileName in args) {
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
NSError *error = nil;
NSString *fileContents = [[[NSString alloc] initWithContentsOfFile:fileName
encoding:NSUTF8StringEncoding error:&error] autorelease];
/* Process the string, creating and autoreleasing more objects. */
[loopPool drain];
}
/* Do whatever cleanup is needed. */
[pool drain];
exit (EXIT_SUCCESS);
}
void main()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *args = [[NSProcessInfo processInfo] arguments];
NSString *fileContents = [[NSString alloc] autorelease];
for (NSString *fileName in args)
{
// NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
NSError *error = nil;
fileContents = [fileContents initWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:&error];
/* Process the string, creating and autoreleasing more objects. */
//[loopPool drain];
}
/* Do whatever cleanup is needed. */
[pool drain];
exit (EXIT_SUCCESS);
}
Do the two pieces achieve the same result?
No. It's bound to blow up and/or leak when fileContents = [fileContents ... is called the second time. Implementations assume their instance's memory is zeroed because that is guaranteed by the runtime.
Even if one initializer is proven to work without issue or leaks, many of them will not.
Don't try to 'renew' your objects like this - just please do it the normal way =)
The sequence (in a non-gc environment) should be: 1) alloc 2) init...(using designated initializer) 3) dealloc.
Do the two pieces achieve the same memory management result? ( as far memory cleaning up, leaking, etc.)
No. In addition to what is outlined in #1, you should not assume the address returned from alloc will be the same returned from the initializer. The initializer may choose to destroy the result of alloc and create or return another allocation. In this case, you will introduce a reference count imbalance (effect: leak and/or zombie).
Does the 2nd code below violate anything as far as best practices?
NSString *fileContents = [[NSString alloc] autorelease]; is weird, very unconventional. The first time I read it, I missed the error because it is so conventional for init...] to be placed between alloc and autorelease.
Does the 2nd code below violate anything as far as Performance?
Performance may suffer by removing the autorelease pool from the inner loop. When large allocations and/or high iterations occur, it's best to create small localized pools, like the original.
To answer your questions:
1) Do the two pieces achieve the same result?
No, they don't, mainly because the second example is incorrect, on two accounts.
Firstly, NSString *fileContents = [[NSString alloc] autorelease] makes very little sense. This line essentially allocates room for a string, and without even initializing it (and increasing its initial retain count to 1), telling it to put itself onto an autorelease pool. This is a big no-no.
And second, fileContents = [fileContents initWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:&error] makes just as little sense. You're initializing a new object using old memory that has not been released or reset in any way, which is just undefined behavior. As Sherm Pendley mentioned, you cannot allocate space once and simply reuse that memory without concern, and since you have no idea how NSString is defined internally, this can either simply leak memory or very simply blow up in your face. Another big no-no.
The rest of the code appears to be fine (it does depend on what you're doing in the 'process' step). As others have pointed out, +alloc and -init are almost always paired with each other, but not just because of convention, but because that this pairing is simply the right thing to do. You must +alloc memory before you can begin to use it, and you must -init to get that memory zeroed and in the right condition to run properly. Any other combination might not be fit for use.
2) Do the two pieces achieve the same memory management result? ( as far memory cleaning up, leaking, etc.)
No, they definitely do not. The second one will leak large amounts of memory, and very well might not even run. The first once is definitely okay, but might not run efficiently due to the use of inner autorelease pools.
3) Does the 2nd code below violate anything as far as best practices? Performance?
Yes, it does, and in fact, even the first one might not run efficiently. Creating an inner autorelease pool might not be in your best interest, and might even hinder your program. The venerable Mike Ash did some testing with autorelease pools, and the results are a little surprising. It turns out that differently-sized autorelease pools will work better on different computers (back then, on his old computer, 100 objects was the most efficent per pool; for me, 10000 objects works a little bit better, and even then only marginally better than 1000 objects)

What's the magic of NSAutoreleasePool in Objective-C/cocoa framework?

I found an example of Objective-C/cocoa framework has the following code.
int main()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Create an array
NSArray *month = [NSArray arrayWithObjects:# ... nill];
[pool drain];
}
Q1 : What's the magic behind this (Why do I need to have the NSAutoreleasePool code?)? What magic is happening between the NSAutoreleasePool and pool drain block? I see I don't need to release*month myself. Is this because it's inside the NSAutoreleasePool and pool drain block?
Q2 : With Xcode, I'm already given the main() function. In this case, how can I use the NSAutoreleasePool and pool drain?
For example :
int main(int argc, char *argv[])
{
//NSAutoreleasePool *pool = [[[NSAutoreleasePool] alloc] init];
return NSApplicationMain(argc, (const char **) argv);
}
Q1: The magic is that NSObject -autorelease instance method calls NSAutoreleasePool +addObject: class method. The NSObject instance is pooled in the current NSAutoreleasePool instance. And NSAutoreleasePool -drain instance method calls release method of pooled instances.
It is not the exactly same between Cocoa implementation of Apple and GNUstep, but it is similar.
NSObject.m
NSAutoreleasePool.m
I'm not sure why month is not released, it should be release by drain.
Q2: You can use NSAutoreleasePool wherever you want to use at. Instantiate a NSAutoreleasePool means the current pool will be changed by the new instance. drain will go back the current pool to the previous instance.
Besides NSApplicationMain never returns. It calls the exit function to exit the application and terminate the process.
Q1:
You don't need to release the month instance in the example you give because the NSArray class method you're calling (arrayWithObjects:) returns an instance that is autoreleased. By convention in Cocoa, class methods that start with the name of the class will return autoreleased instances of that class. These examples:
[NSString stringWithFormat:#"Holla %#", #"back girl!", nil];
[NSArray arrayWithObjects:#"Holla", #"back", #"girl!", nil];
Will both return instances of their respective objects that are autoreleased.
I'm fairly new to Objective C, but let me give this a crack:
The autorelease pool is a way for Objective C to handle garbage collection in a somewhat easier way than manually.
It does this by counting references, or in this case every time you call "retain" or "release".
So if you have an instance of an object in "a", you could do:
This puts it into the AutoreleasePool:
[a autorelease];
This tells the autorelease pool that you want to hold on to it for a while:
[a retain];
When you call [pool drain] now, it will notice that you have one reference to a, and it won't deallocate the memory. However, if you later call [a release], the next time [pool drain] is called, it'll see that there are no further references to a remaining, and deallocate the memory.
I have a sneaking suspicion that I just talked myself in circles without making a whole lot of sense, but here is the wikipedia article on reference counting: http://en.wikipedia.org/wiki/Reference_counting

Multithreading and autorelease pool

As I'm mastering my skills with multithreading with GCD, I've come across some question. Suppose you have the following method:
- (void)method {
NSString *string= [NSString string]; //will be autoreleased
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//very very lengthy operation...
NSLog(#"%#", string); //is it safe?
});
}
I'm wondering if this is correct, because I think I should have retained string before the block execution: in fact I fear that the event loop finishes and sends string an autorelease message before using string in the block. That would crash the program.
Am I right? Should I send a retain and a release message to string or this is the correct implementation?
Thanks in advance!
I'm wondering if this is correct, because I think I should have retained string before the block execution: in fact I fear that the event loop finishes and sends string an autorelease message before using string in the block.
Fear not:
A block captures the scope of the surrounding method/function in that it automatically retains any object-variable that is used inside of the block. Be aware of that when you use self inside of a block, as this may greatly affect the lifetime of the object!
There is one exception to this rule, and that are variables declared as
__block SomeObjectPointerType variableName
Update
Because there’s a new comment on this answer, I should probably add that things changed a little with the introduction of ARC:
Under ARC all object variables default to __strong, and this holds for variables marked with __block as well. If you want to avoid strong capturing of a variable in a block, you should define a local variable that is __weak.
End Update
If you like to learn more about blocks, bbum gave an excellent session called Introducing Blocks and Grand Central Dispatch on iPhone at WWDC 2010.
The "Block Details" section starts at 11:30.
The concern is; when an autorelease object releases?
NSString *myString= [NSString stringWithFormat: #"%#", stringVariable];
The myString depends upon stringVariable, whenever stringVariable releases the myString immediately releases.
NSString *myString= [NSString stringWithString: #"stringVariable"];
In practice it is observed the myString might be releases just after the completion of the method.
Now if you change your code and use NSAutoReleasePool
- (void)method {
NSAutoreleasePool pool = [[NSAutoreleasePool alloc] init];
NSString *string= [NSString string]; //will be autoreleased
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//very very lengthy operation...
// string will be released here
[pool release];
NSLog(#"%#", string); // it is not safe?
});
}
The autorelease objects released when the auto release pool releases in which they exists or when the object releases on which they depends.
Now if you are using the method in a thread you should use auto release pool inside it.
- (void)method {
NSAutoreleasePool pool = [[NSAutoreleasePool alloc] init];
// lengthy operations ...
[pool release];
}

Assign nil to NSString within Autorelease pool

I'm making a great deal of NSString manipulations within an autorelease pool. Problem is my program will sometimes crash before the pool drains. I'm wondering if there is a way to circumvent this problem by assigning nil to NSString. The assignment to userLetters happens a lot. See code below
Before
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
usersLetters = [usersLetters stringByReplacingCharactersInRange:NSMakeRange(indexUser, 1) withString:#"*"];
[pool drain];
After
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *temp = [usersLetters stringByReplacingCharactersInRange:NSMakeRange(indexUser, 1) withString:#"*"]; //remove that found character so it can't be reused again
usersLetters = nil;
usersLetters = temp;
temp = nil;
[pool drain];
I doubt what assigning to nil will help in what you want to achieve.
(I assume you mean that your program crashes because the memory is exhausted, otherwise, it is much more likely that you released to often somewhere, you should also run the Status Analyzer over your code.)
What you can do is to send a retain message to all objects that you still need (in your case usersLetters) and drain the pool afterwards. The objects that you still need should then have a retain count of 1, all other autoreleased objects should have been deallocated.
In your case, this would be
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
usersLetters = [[usersLetters stringByReplacingCharactersInRange:NSMakeRange(indexUser, 1) withString:#"*"] retain]; //sending retain to an object increases its retain count by 1 and returns the object itself
// some more stuff that needs memory
[pool drain];
// ...
[usersLetters release];
[pool release];
You don't mention if your project targets iOS or Mac OS X. If the latter, the best way to resolve this issue may be to simply use garbage collection.
If GC is not an option (which it is not on iOS), the idiomatic way to deal with this is to wrap a nested autorelease pool around your inner, fast-allocating operations. In this case you must retain any objects which need to outlive the nested pool, as mrueg has explained.