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.
Related
This question already has answers here:
Objective C NSString* property retain count oddity
(9 answers)
Closed 9 years ago.
here is the following program about increasing d retain count value of a NSString type variable
in interface part I have declared
#property (strong,nonatomic)NSString *str1;
#property (strong, nonatomic)NSString *str2;
-(IBAction)goBtn:(id)sender;
and ind implementation part I have defined following
- (IBAction)goBtn:(id)sender {
self.str1=[[NSString alloc]init];
self.str1=self.str2;
self.str2=[self.str1 retain];
self.str2=[[NSString alloc]init];
self.str2=self.str1;
self.str1=[self.str2 retain];
self.str2=[self.str1 retain];
NSLog(#"retain count is %i", self.str1.retainCount);
NSLog(#"retain count of str2 is %i", self.str2.retainCount);
}
but the output is
retain count is 0
retain count of str2 is 0
why is this happening?? is there anything wrong in codes???
You are sending a lot of messages to nil and that is why you are getting a 0 for the retain count.
Here I wrote down your code again with the new values for your variables when they change:
str1 and str2 are nil
self.str1=[[NSString alloc]init];
str1 is empty string
self.str1=self.str2;
str1 is nil
self.str2=[self.str1 retain];
self.str2=[[NSString alloc]init];
str2 is empty string
self.str2=self.str1;
str2 is nil
self.str1=[self.str2 retain];
self.str2=[self.str1 retain];
In the end both str1 and str2 are nil giving you a zero retain count.
But even if you didn't overwrite your new strings with nil every time you wouldn't get the expected result. Lets consider this:
self.str1 = [[NSString alloc] init]
self.str2 = [[NSString alloc] init]
If you look at their retain count you'll get 18446744073709551615 (on Mac OS X, 64 bit) for each. If you then look at the values of the pointers you'll see that they both are equal, so you got the same empty NSString object both times you called [[NSString alloc] init].
That actually makes sense. NSString objects are immutable, that means once they are created they cannot ever change. So there is no point in wasting memory on multiple identical copies of the empty string.
Some of those shared instances return the biggest possible value from their retainCount method to show the fact that they are singletons. But not all of them.
So the retain count of objects is not very useful. Some objects lie about it. And in real apps it still often is not what you'd expect. Sometimes the system holds on to objects for some time, even if you didn't retain it yourself.
But I guess you are trying to learn how the retain/release memory model works (which is necessary, even if you are using ARC). For this you can get away with querying the retain count. But then you should use the base class NSObject directly, because it doesn’t do any special tricks with the retain counter. And you need to keep in mind that as soon as you pass your test objects to some system methods your retain count could be something unexpected later. Always keep in mind to never query the retain count in a real app - it is useless.
Retain count is meaningless. Don't worry about it. It gets into a lot of complicated factors like the fact that NSString is a class cluster and the implementation details are really not your problem.
More importantly, your property is declared incorrectly.
Automatic Retain Count (ARC)
#property (strong, nonatomic) NSString *ARCString;
Retain/Release
#property (retain, nonatomic) NSString *retainString;
Further discussion
As Sven (below) points out retain and strong are synonymous technically. However, I think it is important to distinguish when code is under ARC or Retain/Release. Some general best practices:
Only refer to the ivar in init and dealloc using _ivar and here use a call to retain/release if not using ARC. No need for dealloc under ARC.
- (id)initWithString:(NSString *)string
{
self = [super init];
if (self != nil) {
_retainString = [string retain]; // Adds 1 to retain count
}
return self;
}
- (void)dealloc
{
[_retainString release]; // Decrement retain count by 1
[super dealloc];
}
The rest of the time make the call to the getter/setter using self.ivar. This takes care of the correct behavior automatically.
- (void)doSomethingWithString:(NSString *)string
{
self.retainString = string; // Adds 1 to retain count
}
If and when you decide to override the getter/setter in your declared property, then you will refer to the _ivar and manually call retain or release. If using ARC the call to retain/release is unnecessary.
- (void)setRetainString:(NSString *)string
{
if (_retainString != string) {
[_retainString release];
_retainString = [string retain];
}
}
You should always Analyze your code to verify you haven't screwed something up in an obvious way. It will often reveal failures in your logic.
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.
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
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.
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];