iPhone Autoreleasepool and allocations - iphone

I've been reading about autoreleasepool but there is a point which is a bit unclear to me. I have some functionality using threads that required seperate memory managment using autoreleasepool.
In the following example is correct
-(void) doSomething {
NSAutorelease *pool = [[NSAutorelasepool alloc] init];
NSString *myString = #"Hello";
[pool release];
}
Is this correct?
-(void) doSomething {
NSAutorelease *pool = [[NSAutorelasepool alloc] init];
NSString *myString = [[NSString alloc] initWithString:#"Hello"];
[pool release];
}
or this?
-(void) doSomething {
NSAutorelease *pool = [[NSAutorelasepool alloc] init];
NSString *myString = [[NSString alloc] initWithString:#"Hello"];
[myString release];
[pool release];
}
My question is owned objects created in the scope of the autorelease pool need to be relased specifically or are the taken care of when the autorelasepool is been released?
Teo

Autorelease pool handles the autoreleased objects. If you own an object (via alloc or copy or retain) then you must release it. So your 2nd example is not correct. As you have allocated the string, you own it and you must release it.
An autorelease pool is created for the main thread. (You can look into the main function if you want). Every thread need its own autorelease pool to manage autoreleased objects. That's why if you create another thread then you must create an autorelease pool for that thread. Even if you don't create autoreleased object in the thread, you should create this as the library calls in that thread may create autoreleased objects. Even if you are sure that no library calls are making autoreleased objects then you also should create them as that is the best practice, specially if you are working on big project which is developed and maintained by multiple people.

You only need to create your own autorelease pool when you are creating a bunch of
autoreleased objects you want to garbage collect immediately. However, you are correct in that you don't want to reference any "autoreleased" objects you create after you release the pool. Autoreleased objects (which you don't retain) are destroyed when the pool is drained.
Since none of the objects in your example are autoreleased, creating your own autorelease pool is essentially a no-op.

Neither of your examples needs an autorelease pool. Autorelease pools only take care of autoreleased objects:
NSArray *foo = [NSArray array];
NSObject *bar = [[[NSObject alloc] init] autorelease];
Your first string is initialized using a string literal and therefore is probably special with respect to memory management (maybe someone else knows more). Your second string leaks, the pool does not make a difference. Your third string is released correctly, again the pool does not make a difference.
This is where you would need a pool:
- (void) someMethodThatRunsOnAThread {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *foo = [#"foo" uppercaseString];
[pool drain];
}
Here the foo string would leak if the pool wasn’t there. Note that I’m calling drain instead of release on the pool – on iOS there’s not a difference, but in garbage-collected environments the two differ, so it’s probably better to get in the habit of calling the right one.
Also note that you may need a pool even though you don’t autorelease any objects yourself, there could be many memory operations done somewhere in the code you’re calling in your method.

Think that this should be something like this:
-(void) doSomething {
NSAutorelease *pool = [[NSAutorelasepool alloc] init];
NSString *myString = [[[NSString alloc] initWithString:#"Hello"] autorelease];
// or create string like this (automatically autoreleased)
NSString *myString = [NSString stringWithString:#"Hello"];
[pool release];
}
You must send autorelease message, to objects inside autorelease pool. They will be released when release message is sent to pool.

Related

Memory leak of an NSMutableArray using Instruments

According to the leak instrument in XCode it's saying this line is giving a memory leak (100%)?
self.unsentPatients = [[NSMutableArray alloc] initWithArray:[defaults arrayForKey:UNSENT]];
I'm correctly releasing etc. on dealloc (which is definitely being ran) so I don't understand where I am going wrong?
It's only a small leak and Analysis doesn't come up with anything, but nonetheless it's still a leak.
Kind regards,
Dominic
There are many things wring with this code.
I'm assuming that the property is retaining the value, then you should not assign the value the way you are doing now, but more like:
NSMutableArray *temp = [[NSMutableArray alloc] initWithArray:[defaults arrayForKey:UNSENT]];
self.unsentPatients = temp;
[temp release], temp = nil;
or
self.unsentPatients = [[[NSMutableArray alloc] initWithArray:[defaults arrayForKey:UNSENT]] autorelease];
You should also avoid using the self. syntax in dealloc or init, which will call a mutator.
In multithreaded environment this could give problems.
So the correct dealloc would be:
- (void) dealloc {
[unsentPatients release], unsentPatients = nil;
[super dealloc][;
}

Why no retain is needed in my code but it works

I have a class
#implementation MyClass
- (void) foo
{
ivar = [NSString stringWithString:#"ivar"];
}
- (void) bar
{
NSLog(#"%#", ivar);
}
And main.m
MyClass * m = [[MyClass alloc] init];
[m foo];
[m bar];
Why no retain is needed for stringWithString?
Can you show me an example where retain is needed?
Its because the autorelease pool had no time to drain its content. Here is a crashing example:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
MyClass *m = [[MyClass alloc] init];
[m foo];
[pool drain];
[m bar];
The autorelease pool that holds the string in your example belongs to 99% to the current runloop which creates a new pool at the begin of the event loop and then drains it at the end.
Why no retain is needed for stringWithString?
Because the autorelease pool is not being drained between line 2 and line 3 (as it would be in a Cocoa app as soon as your code returns control to the run loop).
You can start by reading Memory Management Programming Guide and look at this tutorial.
Have a look at Memory Management Rules from Apple. In your case, you did not alloc/retain/net the NSString so you don't "own" it and therefore you do not need to release it.
Internally, NSString would return you a autoreleased object. If you don't retain it then you'll lose reference to it if it gets dealloced by an autorelease pool.

Question about memory usage

I have the following method:
+(NSMutableDictionary *)getTime:(float)lat :(float)lon {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:hour forKey:#"hour"];
[dictionary setObject:minute forKey:#"minute"];
[dictionary setObject:ampm forKey:#"ampm"];
return dictionary;
}
A lot of the method is chopped off, so I think I need the pool for some other stuff in the method. Here's my question. I know that I need to release the following objects:
[dictionary release];
[pool release];
However, I can't release the dictionary before I return it, but as soon as I return it the rest of the method isn't performed. What should I do?
You could always autorelease the dictionary, thereby ensuring it is kept in memory at least until getTime:: returns. This conforms well to the memory paradigm on Cocoa, where a method which returns an object which it creates (but does not own), calls autorelease on it when it no longer needs it.
Of course, make sure to retain that dictionary in any code that receives it from getTime::.

why does it works fine without 'retain' the object?

Here i used auto-release for 'tempString' in the method 'test'. According to the rule, i should use "[temp retain]" in the main . But i didnt use it. still it works fine and prints the output. Then what is the need of "retain"? Can anyone pls tell me the reason? Thanks in advance.
-(NSMutableString *) test : (NSMutableString *) aString{
NSMutableString *tempString=[NSMutableString stringWithString:aString];
[tempString appendString:#" World"];
return tempString;}
int main (){
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
MemoryMgmt *memoryMgmt=[[MemoryMgmt alloc] init ];
NSMutableString *str1 =#"Hello";
NSMutableString *temp = [memoryMgmt test: str1];
NSLog(#" %#",temp);
[pool drain];
return 0;
}
stringwithString should return an autoreleased NSMutableString, but that doesn't actually get released until the NSAutoReleasePool drains. You are using the object while the pool is still retaining it and only draining the pool afterwards, releasing the object.
When you receive an autoreleased object from somewhere, you should only retain it if you intent to keep track of the object beyond the current variable scope. If you were to retain the object, but your reference were to go out of scope (as it does after your current function call completes), you would leak the object.
What you are doing here is actually correct, since you don't keep the reference to temp anywhere but in your local scope.
When you auto-release an object it will release at the end of the run-loop when the pool is drained or released...In your case, since you start a new thread, you manage the autorelease pool, the string temp does not release until you drain your pool, therefore when you use it, it is still valid...hope that helps
That works because the Autorelease pool doesn't get emptied until the end of the tool's execution. However, it is in fact correct usage: you return an autoreleased object from a method that doesn't claim to be passing ownership to the caller. Some people do
return [[tempString retain] autorelease];

Simple problem with NSString

I have this userInputstring in the header that will be modified and used by multiple methods in the .m file
.h
NSString *userInputString;
-(void)main;
-(void)method1;
-(void)method2;
.m
-(void)main{
[self method1];
[self method2];
}
-(void)method1{
NSString *localString = #"something";
userInputString = localString;
//do something else with it
}
-(void)method2{
NSString *localString = [NSString stringWithFormat:#"%# insert something",userInputString];
userInputString = localString;
[someOtherMethod:userInputString];//Crash
}
but I kept getting memory leak problems. What's the proper way to set it up? Im new to objective c.
I don't know where or how to release
Right, you first need to familiarise yourself with the Cocoa Memory Management Rules.
In summary, if you obtain an object by alloc, a method containing "copy", a method starting with "new" or if you retain it, you need to release or autorelease.
Take method1:
-(void)method1{
userInputString = #"something";
}
userInputString was not obtained with alloc, new or copy, nor have you retained it. Therefore you do not own it so you must not release it. If you had done this:
userInputString = [#"foo" copy];
or this:
userInputString = [[NSString alloc] initWithString: #"foo"];
or this:
userInputString = [#"foo" retain];
you do own the string therefore you must release or autorelease it.
When you release it depends on its scope. If it's a local variable, you must release or autorelease it before the block it is declared in exits. If it is an instance variable, you must release it before the object it is in is deallocated. i.e. you must release it in the dealloc method for the object. In all cases, if you overwrite an object you own, you must release it first. So:
userInputString = [someOtherString copy]; // you own userInputString
// do some stuff
[userInputString release]; // you no longer own it
userInputString = [someOtherString retain];// overwrite the pointeer with something else
This is one of the reasons for adding getters and setters for instance variables. Every time you set a new value, you have to release the old value and retain the new value (making sure that the old bvalue and new value are different), so this is encapsulated in the setter. A synthesized property adds this code automatically.
Try to use autorelease pool:
int main()
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
....
// Your code here
[pool drain]
return 0;
}
#"blablabl" is a shorthand to create an autoreleased NSString from a constant string. If if you don't have an autorelease pool in the thread you are running, those NSString object won't ever be released and of course your create a leak.
Either create an autorelease pool as Sumai suggest or release those objet's memory yourself. (tip: create an NSAutorelesePool ;-) )