what does #autoreleasepool do? - iphone

I am using ARC and i know the autoreleasepool sends release to all elements inside it. Consider the following example.
-(NSString*)someMethod{
NSString *string1=#"sample text inside string 1"; // string1 add to main autorelease pool
NSString *string2=[[NSString alloc] init]; // string2 retain count is 1
string2=#"sample text inside string 2"; // just assigning
return string1;
}
-(void)viewDidLoad{
NSString *returnedString=[self someMethod];
}
1. so my question is how do i completely release string2 in
someMethod?
2. How to completely release string1 from viewDidLoad method completely?
Note: I am using ARC
if i use #autoreleasepool in someMethod then i think it will destroy both string1 and string2. wont it?
And what will be the effect of using #autoreleasepool in someMethod
-(NSString*)someMethod{
#autoreleasepool{
NSString *string1=#"sample text inside string 1"; // string1 add to main autorelease pool
NSString *string2=[[NSString alloc] init]; // string2 retain count is 1
string2=#"sample text inside string 2"; // just assigning
}
return string1;
}

First of all,
NSString *string2=[[NSString alloc] init];
string2=#"sample text inside string 2";
string2 is not an object itself. It is a pointer to an object. So here you create an object, get a pointer to it, and then immediately replace it with a pointer to another string. If you didn't use ARC you would leak memory here. Take a look at #Anoop Vaidya's answer for more details about it.
As for your questions: when you use ARC, the compiler automatically tracks objects and releases them when they are no longer used. So you don't have to release it manually. You could assign a pointer to nil, but as soon as I remember it is not necessary.
The code from your second example won't compile, because string1 is declared inside the autorelease scope. And actually this #autorelease here doesn't make any difference since you don't create autoreleased objects inside it.
This question contains more details about using autorelease pool with ARC.
And Apple's official documentation is probably the best I've ever seen, so please feel free to have a look at their Advanced memory management programming guide. It isn't too long, and it explains everything in details :)

You can't release any object, instance if you are using ARC. It is handled by complier itself when you use ARC.
So, even string will be released the same way.

You don't need to release it ,it will automatically done by ARC.
it will give an error if you try to release any object while using ARC.

NSString *string2=[[NSString alloc] init]; // string2 retain count is 1
string2=#"sample text inside string 2";
Bad way to doing.
Instead do this way
NSString *string2=[[NSString alloc] initWithString:#"sample text inside string 2"];
Or even
NSString *string2=#"sample text inside string 2";
string1 is in autoreleased mode, you dont have to release it.
As you are using ARC(Automatic Reference Counting). You never release object. The compiler takes care of it.

Related

IPhone Objective C Memory Allocation

I understand that when using Alloc, new or copy you own the object and need to release the object. I understand that if I retain an object that I need to release it.
But if I have the following statment at the end of a method:
return [[UIImage alloc] initWithContentsOfFile:path];
I own the UIImage object becaused I allocated the memory space, but I dont have a reference to it anymore because it was returned to the caller. In my dealloc() method I can't release it, since I dont have a reference.
So my question is, is this correct:
return [[[UIImage alloc] initWithContentsOfFile:path] autorelease];
I beleive in this case the caller then can retain the returned object if they like to take ownership and will eventually need to release themselves.
Thanks for your help.
Your assumptions are right. When you're returning an object, you should pass it as an autorelease object.
You use autorelease when you need to send a deferred release message—typically when returning an object from a method...
The whole point of autorelease was built around returning objects.
- (id)bad {
MyObj *obj = [[MyObj alloc] init];
return obj;
}
This code returns everything correctly, but you (as developer) must be sure to release the object later on.
- (id)moreBad {
MyObj *obj = [[MyObj alloc] init];
return [obj release];
}
This code uses the memory as expected, balancing retain and release in one scope, but returned object is garbage now (expect this to crash).
- (id)good {
MyObj *obj = [[MyObj alloc] init];
return [obj autorelease];
}
This code is "delayed release". I.e. you can retain the object at the caller side and the object would be safe. It could surely be broken if you don't have NSAutoreleasePool in scope, but that's a pretty rare condition, and you mostly know when that happens (the most common scenario is to start a new thread where there is no "default" autorelease pool).
So, the common practice is to balance the retain (and retain-like) and release methods in one scope. Next suggestion is to always have objects alloc-init-autoreleased, and switch to distinct releases if you have memory issues (like autoreleasing lots of objects in a loop). Next suggestion is to switch to ARC.
Both answers are correct, you may however not always have a convenience method at your disposal, so what I like to do is what you've done with autorelease:
- (MySomethingClass*)giveMeAFancyObject{
MySomethingClass *obj = [[[MySomethingClass alloc] init] autorelease];
obj.name = #"Something";
// do some setting up maybe
return obj;
}
If you use release, however, the string will be deallocated before it is returned (and the method would return an invalid object). Using autorelease, you signify that you want to relinquish ownership, but you allow the caller of the method to use the returned string before it is deallocated.
Why trying to alloc it? Just say:
return [UIImage imageWithContentsOfFile:path];
Nothing to alloc - nothing to release.
Also, this is the best option while using ARC, where a releasing attempt leads to error.

#property/#synthesize question

I'm going through all of my documentation regarding memory management and I'm a bit confused about something.
When you use #property, it creates getters/setters for the object:
.h:
#property (retain, nonatomic) NSString *myString
.m:
#synthesize myString
I understand that, but where I get confused is the use of self. I see different syntax in different blogs and books. I've seen:
myString = [NSString alloc] initWithString:#"Hi there"];
or
self.myString = [NSString alloc] initWithString:#"Hi there"];
Then in dealloc I see:
self.myString = nil;
or
[myString release];
or
self.myString = nil;
[myString release];
On this site, someone stated that using self adds another increment to the retain count? Is that true, I haven't seen that anywhere.
Do the automatic getters/setters that are provided autorelease?
Which is the correct way of doing all of this?
Thanks!
If you are not using the dot syntax you are not using any setter or getter.
The next thing is, it depends on how the property has been declared.
Let's assume something like this:
#property (nonatomic, retain) Article *article;
...
#synthesize article;
Assigning something to article with
self.article = [[Article alloc] init];
will overretain the instance given back by alloc/init and cause a leak. This is because the setter of article will retain it and will release any previous instance for you.
So you could rewrite it as:
self.article = [[[Article alloc] init] autorelease];
Doing this
article = [[Article alloc] init];
is also ok, but could involve a leak as article may hold a reference to an instance already. So freeing the value beforehand would be needed:
[article release];
article = [[Article alloc] init];
Freeing memory could be done with
[article release];
or with
self.article = nil;
The first one does access the field directly, no setters/getters involved. The second one sets nil to the field by using a setter. Which will release the current instance, if there is one before setting it to nil.
This construct
self.myString = nil;
[myString release];
is just too much, it actually sends release to nil, which is harmless but also needless.
You just have to mentally map hat using the dot syntax is using accessor methods:
self.article = newArticle
// is
[self setArticle:newArticle];
and
myArticle = self.article;
// is
myArticle = [self article];
Some suggestions on reading, all official documents by Apple:
The Objective-C Programming Language
Dot Syntax
Declared Properties
Memory Management Programming Guide
Object Ownership and Disposal
Using Accessor Methods
When you create a retain setter, you're creating something like this:
- (void)setString:(NSString *)someString {
if (someString != string) {
[string release];
[someString retain];
string = someString;
}
}
If you don't use the setter, the new value is not getting that retain—you don't "own" that string, and because it's all references, if the original string is released, you might be facing a null reference, which will lead to an EXC_BAD_ACCESS. Using the setter ensures that your class now has a copy of that value—so yes, it does increment the retain count of the new value. (Note that using the getter is a convention of OOP—that outsiders should not be able to directly touch the ivar. Also in your getter you can modify the value, maybe returning an NSArray when your ivar is an NSMutableArray, for example).
You shouldn't autorelease in a setter—Apple has used it in their sample code, but a thing to keep in mind is that setters are called a lot—millions of times, potentially. All of those objects are going into the same autorelease pool, so unless you create your own and/or regularly flush it, you'll have a ton of elements in your pool, all unneeded but still taking up RAM. Much better to simply release.
As for dealloc, trace back through that setter. If you send a release directly, it's obvious—you release that object. But if you write self.string = nil;, what you're doing is this:
The nil value is not the same, so you enter the if block
You release the old value—what you want to do
You retain nil: messages to nil do nothing, and you don't crash
You set nil, which doesn't take up any memory, to the string, which is now effectively empty
As a matter of convention, I use release in my dealloc method, because release seems more final, and dealloc is the final method call your object will receive. I use self.string = nil; in viewDidUnload and the memory warning methods.
Hope this helps!
In addition to Nick's answer - synthesized getters/setters don't provide autorelease (btw, what's the big idea of doing this? Well, you can use getter as a factory, but it's not a common way in Objective C).
Then in dealloc I see:
self.myString = nil;
or
[myString release];
or
self.myString = nil; [myString
release];
In dealloc it doesn't really matter which form of release you're using. But the good way is to nil your fields when releasing them :) I prefer to use self.myString = nil; in dealloc

How to release an object in a forin loop?

I'm new to cocoa / objective-c and i'm struggeling with the releases of my objects. I have the following code:
gastroCategoryList = [[NSMutableArray alloc] init];
for (NSDictionary *gastrocategory in gastrocategories) {
NSString *oid = [gastrocategory objectForKey:#"id"];
GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:#"name"]];
[gastroCategoryList addObject:gc];
}
The analyzer shows me that the "gastrocategory" defined in the for is a potential memory leak. But i'm not sure if i can release this at the end of the for loop?
Also at the following code:
- (NSArray *)eventsForStage:(int)stageId {
NSMutableArray *result = [[NSMutableArray alloc] init];
for (Event *e in eventList) {
if ([e stageId] == stageId) {
[result addObject:e];
}
}
return result;
}
The Analyzer tells me that my "result" is a potential leak. But where should I release this?
Is there also a simple rule to memorize when i should use assign, copy, retain etc. at the #property ?
Another problem:
- (IBAction)showHungryView:(id)sender {
GastroCategoriesView *gastroCategoriesView = [[GastroCategoriesView alloc] initWithNibName:#"GastroCategoriesView" bundle:nil];
[gastroCategoriesView setDataManager:dataManager];
UIView *currentView = [self view];
UIView *window = [currentView superview];
UIView *gastroView = [gastroCategoriesView view];
[window addSubview:gastroView];
CGRect pageFrame = currentView.frame;
CGFloat pageWidth = pageFrame.size.width;
gastroView.frame = CGRectOffset(pageFrame,pageWidth,0);
[UIView beginAnimations:nil context:NULL];
currentView.frame = CGRectOffset(pageFrame,-pageWidth,0);
gastroView.frame = pageFrame;
[UIView commitAnimations];
//[gastroCategoriesView release];
}
I don't get it, the "gastroCategoriesView" is a potential leak. I tried to release it at the end or with autorelease but neither works fine. Everytime I call the method my app is terminating. Thank you very much again!
In your loop, release each gc after adding it to the list since you won't need it in your loop scope anymore:
gastroCategoryList = [[NSMutableArray alloc] init];
for (NSDictionary *gastrocategory in gastrocategories) {
NSString *oid = [gastrocategory objectForKey:#"id"];
GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:#"name"]];
[gastroCategoryList addObject:gc];
[gc release];
}
In your method, declare result to be autoreleased to absolve ownership of it from your method:
NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease];
// An alternative to the above, produces an empty autoreleased array
NSMutableArray *result = [NSMutableArray array];
EDIT: in your third issue, you can't release your view controller because its view is being used by the window. Setting it to autorelease also causes the same fate, only delayed.
You'll have to retain your GastroCategoriesView controller somewhere, e.g. in an instance variable of your app delegate.
BoltClock's answer is spot-on as to the first part of your question. I'll try to tackle the rest.
Assign is for simple, non-object types such as int, double, or struct. It generates a setter that does a plain old assignment, as in "foo = newFoo". Copy & retain will, as their names imply, either make a copy of the new value ("foo = [newFoo copy]") or retain it ("foo = [newFoo retain]"). In both cases, the setter will release the old value as appropriate.
So the question is, when to copy and when to retain. The answer is... it depends. How does your class use the new value? Will your class break if some other code modifies the incoming object? Say, for example, you have an NSString* property imaginatively named "theString." Other code can assign an NSMutableString instance to theString - that's legal, because it's an NSString subclass. But that other code might also keep its own reference to the mutable string object, and change its value - is your code prepared to deal with that possibility? If not, it should make its own copy, which the other code can't change.
On the other hand, if your own code makes no assumptions about whether theString might have been changed, and works just as well whether or not it was, then you'd save memory by retaining the incoming object instead of unnecessarily making a copy of it.
Basically, the rule, which is unfortunately not so simple sometimes, is to think carefully about whether your own code needs its own private copy, or can correctly deal with a shared object whose value might be changed by other code.
The reason you can release gc after it is added to the gastroCategoryList is that when an object is added to an array, the array retains that object. So, even though you release your gc, it will still be around; retained by the gastroCategoryList.
When you are returning a newly created object from a method, you need to call autorelease. This will cause the object to be released only after the runtime leaves the scope of the calling method, thereby giving the calling method a chance to do something with the returned value.
Note that if your method starts with the word copy or new, then you should not autorelease your object; you should leave it for the calling method to release.
As for copy vs retain vs assign... as a general rule, copy objects that have a mutable version, such as NSArray, NSSet, NSDictionary, and NSString. This will ensure that the object you have a pointer to is not mutable when you don't want it to be.
Otherwise, use retain whenever you want your class to be ensured that an object is still in memory. This will apply to almost every object except for objects that are considered parents of your object, in which case you would use assign. (See the section on retain cycles here).
Also note that you have to use assign for non-object types such as int.
Read through the Memory Management Programming Guide a bit; it's quite helpful.

Basic retain, autorelease question

retain and autorelease questions.
// A
UIView *temp = [[UIView alloc] init];
myView = temp;
[temp release];
// B
myView = [[UIView alloc] init];
Do the two codes have no differences?
NSString *str = [NSString stringWithString:#"Hello"];
NSString *str = #"Hello";
And these two? I'm not sure about retain count yet. Thank you.
For the first example, they are very different. In first code chunk, the UIView given to temp has a retain count of 1 (thanks to alloc). When you release it on the third line, the MyView variable is now bad, because the object could be destroyed. If you want MyView to keep it, do:
MyView = [temp retain];
The second part of the first example will create an entirely new instance of a UIView, which has no relationship to temp.
In the second example, the stringWithString method will autorelease your string, meaning that it will be automatically released for you when the "release pool" is released, much later. You don't have to worry about releasing it. In the second line, however, the string is statically allocated. Retain counts and releasing are totally unnecessary with them.
Forgot to mention... check out the answer to this question for more about the retain/release rules.
First part: It's not the same!
MyView will be released too, because you're just copying the pointer (retain count 0).
In the second code MyView will have retain count of 1.
Second part: It's basically the same.
Remember that the reference MyView just points to temp. So as soon as you release temp, this also affects MyView.
The [NSString stringWithString:] is mainly used for copying other strings instead of referring to the memory address. E.g:
A:
NSString *string = someOtherString; // Copies the reference to someOtherString;
B:
NSString *string = [NSString stringWithString: someOtherString]; // Makes a copy of the other string.
One useful thing, is that you can NSLog the retaincount, so that you can do testing on your own.
But back to your question...
IF MyView is a property, and you had referenced it with self.MyView and it was declared with retain or copy, your 2 statements are the same. If MyView is just a local variable, your UIView will dealloc when you do
[temp release];
because you have done nothing to increase the retain count since you alloced it.
For your string example...
[NSString stringWithString:#"Hello"];
returns an autoreleased string. if you will need to keep it for a very long time, you'll want to put a retain on it.
The second string example is a statically allocated string, and you do not have to worry about it. retain counts don't apply to them.

NSMutableArray gets corrupted

I'm doing an iPhone application which uses a navigation control to browse through some data. This data is stored in a sqlite database and I have a class which gets it and returns it in a NSMutableArray of NSStrings.
The problem is that in the first screen of the navigation everything works prefectly, but in the second screen (another view which is pushed) the same code fails because the NSMutableArray gets corrupted. In the debugger I can see that it is returned correctly, but when it's time to use it the pointers have become corrupted and the application crashes.
I have put breakpoints in all my functions, and I can't see anywhere where it can get corrupted. And as the first view, which uses the same exact code, even accesing the same eact tables, works correctly I don't really know where to look.
If anyone want to have a look at the code I have uploaded it to my site: http://sachafuentes.com/iBacus.zip
Thanks in advance.
UPDATE:
The problem lies in the function where I get the data, which looks like (this is a simplified version with some pseudo-code).
-(NSMutableArray *) getPaises {
NSMutableArray * paises;
paises = [[NSMutableArray alloc] init];
while( get new row ) {
NSString *aPais = get the value;
[paises addObject:aPais];
[aPais release];
}
return paises;
}
If I comment out [aPais release] everything works, but to me this looks like a memory leak, as the NSString won't be released.
Okay, here's the problem:
NSString *aPais = [NSString stringWithUTF8String:(char*)sqlite3_column_text(compiledStatement, 0)];
By convention, any time that you see an alloc and an init, you need a release somewhere down the road.
By convention, any time that you use an xWithX: style method, the resulting object will be released for you.
Therefore, this statement:
[aPais release];
will cause your method to crash, as the object is released before it should be. Just remove this line, set your NSMutableArray instance to be autorelease-d and you should get better results.
Look for wrong memory management, that's the likeliest cause for crashes. I think you release your objects somewhere where you shouldn't and therefore you have dangling pointers in the array.
Update1
[aPais release] is wrong, as you don't retain it anywhere in this method. Returned values should always be autoreleased. You should have the same amount of retain as release in your code.
(Some people argue that a retain can also be an alloc init, but I always try to use alloc init autorelease, but this is a matter of style.)
BTW
You should autorelease your array, you're only retaining it here with [[alloc] init].
Any object that you alloc and init must be release-d when you're finished with it, or you will have a memory leak.
Since you are passing the reference outside the scope of the getPaises method, you must autorelease the NSMutableArray, or you will have a memory leak:
paises = [[[NSMutableArray alloc] init] autorelease];
Can you please clarify the step here:
NSString *aPais = get the value;
It's not clear what happens in "get the value" and I suspect this is one cause of instability.
I see that the code is (verbatim)
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
NSString *aPais = [NSString stringWithUTF8String:
(char*)sqlite3_column_text(compiledStatement, 0)];
[paises addObject:aPais];
[aPais release];
}
...and it's exactly as #gs puts it. aPais is autoreleased and should not be released.
You can also use a convenience constructor to initialize the NSMutableArray:
NSMutableArray *paises = [NSMutableArray array];
This is equivalent to doing:
NSMutableArray *paises = [[[NSMutableArray alloc] init] autorelease];