NSString *str = [[[[NSString alloc]init]autorelease]autorelease];
str = #"hii";
NSLog(#"%#",str);
Can any one help me to tell about this code. Autoreleasing the object twice what will happened. When i run the code i didn't get any zombie. why it so.
The object gets released twice when the autorelease pool is destroyed, which is probably going to be at the end of the run loop iteration. Why it doesn't crash is, that NSString returns singletons for some instances, for example the empty string you create or string literals (you should NOT depend on it, thats just what currently happens!), these objects won't be deallocated and this is why you don't get a zombie.
First of there is no reason to call autorelease twice.
Once an object is marked as autorelease, calling autorelease on it again will just be ignored. See https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsautoreleasepool_Class/Reference/Reference.html
But in the exmaple you posted you are creating an empty string:
NSString *str = [[[[NSString alloc]init]autorelease]autorelease];
Then you assign an other string to it:
str = #"hii";
This means that the first string you allocated is just going to be leak, you did autorelease it so it will be cleaned up at the end. But there is not reason to allocated the string in fist place.
You could just do:
NSString *str =#"hii";
NSLog(#"%#",str);
Related
I was having an issue with my UPDATE statement as I was telling here: Update issue with sqliteManager
I found out that initWithFormat WORKS
NSString *sqlStr = [[NSString alloc] initWithFormat:#"UPDATE User SET Name = :Name WHERE Id = :Id"];
BUT not stringWithFormat:
NSString* sqlStr = [NSString stringWithFormat:#"UPDATE User SET Name = :Name WHERE Id = :Id"];
Why is this as such? I would like to understand the logic/reasoning behind..
I am guessing that it has to do with the memory management of the string, it might not have been sufficiently retained so it is getting cleaned up before for it is getting used. The difference between the two methods are defined here
I have just found something interesting from this thread: How to refresh TableView Cell data during an NSTimer loop
This, I believe, is the reasoning behind..
I quote what "petergb" said:
[NSString stringWithFormat:...] returns an autoreleased object. Autoreleased objects get released after control returns from the program's code to the apple-supplied run-loop code. They are more or less a convenience so we don't have to release all the little objects that we use once or twice here and there. (For example, imagine how tedious it would be if you had to release every string you created with the #"" syntax...)
We can tell stringWithFormat: returns an autoreleased object because, by convention, methods who's names don't start with alloc or copy always return auto-released objects. Methods like this are said to "vend" an object. We can use these objects in the immediate future, but we don't "own" it (i.e. we can't count on it being there after we return control to the system.) If we want to take ownership of a vended object, we have to call [object retain] on it, and then it will be there until we explicitly call [object release] or [object autorelease], and if we don't call release or autorelease on it before we lose our reference to it by changing the variable to something else, we will leak it.
Contrast with [[NSString alloc] initWithFormat:. This method "creates" an object. We own it. Again, it will be there until we explicitly call [object release].
I'm using a NSMutable String to gain a string back from a database query. I've assigned the variable with #"" and then populate if found from the database. I've tried adding autorelease / release but this causes problems with references to the database call.
Can someone point out my error ?
I would have typed this code but I felt the analyzer arrows were useful.
You're creating an autoreleased NSMutableString and assigning the pointer strDBAAppVer to point to it. But then you throw away the reference to that object, and get the pointer strDBAppVer to point to a new object, an NSString with a retain count of 1.
What I think you want is inside your if statement is something like this:
NSString* databaseField = [[NSString alloc] initWithUTF ...etc.]
[strDBAppVer setString: databaseField];
[databaseField release];
strDBAppVer is first set to [NSMutableString stringWithString:#""], which is reasonable, memory-wise. However, later, you completely re-set the variable to a whole different object, created by alloc/initWithUTF8String:, making strDBAppVer sometimes point to an already-autoreleased object, and sometimes (when the if statement is true) point to an object with retain count +1.
That's why there's a leak but releasing causes issues. If the if statement is true, you've set your variable to point to an object with +1 count, and if it's false, you've set your variable to point to an entirely different object with 0 count.
This looks to me like confusion about mutable strings. Are you aware that, at least in the code posted, you don't actually mutate strDBAppVer? Try this instead:
NSString* strDBAppVer = #"";
Then, inside your if statement,
strDBAppVer = [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statementAppVer,0)];
//Now, realizing that strDBAppVer has just been reassigned to point
//to an entirely new object, one created with alloc/init, and therefore one that
//needs to be released,
[strDBAppVer autorelease];
Note the autorelease is only inside the if statement, so it doesn't accidentally overrelease your original value of #"". (Since constant strings shouldn't be released.)
To me, the following code looks like it will create a leak -- I might be wrong about this though:
-(NSString*) myString{
NSString* foo = #"bar";
return foo;
}
My question is:
1) Will is create a memory leak as foo is not released?
2) If it IS a memory leak then how do I avoid it?
It is not a leak. #"bar" is a statically allocated string and thus foo doesn't need to be retained. You can handle these strings like autoreleased objects although they will resist in memory for the runtime of the application.
You can turn it into a leak by returning [foo retain] or [foo copy].
Technically it makes no sense to retain static variables. But if you copy them, you have to release them.
Short answer. This code will not give a leak.
Long answer:
With NSString it is not always visible leak, because of strings intern and because you do not call alloc/new/copy methods. But yes, this is a classic point of memory leak in general.
There are two ways of dealing with it.
tracing all objects that you are returning from this (or similar) method and releasing them. That's extremely buggy possibility and a very bad one almost every time.
returning autoreleased instance. In fact, you did something like it implicitly here. This string assignment is similar to:
NSString *foo = [NSString stringWithString:#"bar"];
And this one is similar to:
NSString *foo = [[[NSString alloc] initWithString:#"bar"] autorelease];
So, you will return an object, that has retain count 1, but is autoreleased. So, when NSAutoreleasePool will be drained, this object will go away.
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString * str = [[NSString alloc] initWithString:#"test"];
[str release];
int i = 999999999;
while(i-- > 0) {}
NSLog(#"%#", str);
[pool drain];
Output: test
Why didn't release work?
How can I immediately delete the object from memory?
Xcode Version 4.0 iPhone Application
~SOLVED~
Thank's to all for answers.
I've got a lot of useful information about this question. I'm going to use NSString *str = #"text" instead of NSString *str = [[NSString alloc] initWithString:#"text"];
i've understood that release just "marks" memory as "willing to be freed", but not freeing it immediatly
It did work. You have relinquished ownership of that object, and when the system determines that it is no longer owned, it will be marked available for reuse by the system. That may happen immediately, if you were the only owner of the string. It may happen at some later point, if creation of the string caused it to be autoreleased internally. Or, as Dave DeLong points out, the system may optimize it into an object that is never released.
In your case, it's being optimized into a constant string, which will exist for the life of the program. If you were to use an NSMutableString instead of an NSString, you'd see funky behavior that would probably not crash, but wouldn't print what you expected. (See this question for an example.)
If you used an NSArray instead, it would be deallocated when you called release, but you'd still see your NSLog example work correctly until you allocated some other object. Deallocation just marks the memory as available for reuse; it doesn't actually clear it out. So if you passed the array to NSLog, that memory hasn't been changed and thus it still prints correctly.
The key point in all of this, though, is to recognize that calling release will not necessarily cause the object to be deallocated. It may continue to exist for any number of reasons. But once you call release, you have relinquished ownership of the object. If you continue using it after that point, the system is free to do all sorts of weird things at its own will, as demonstrated.
Release does work but what you are attempting to do has undefined behavior, and when using a NSString and a literal you may also get different behavior. What is happening is although your object is released the memory at that location is reclaimable and has not changed and when it goes to print it it is still valid. Since it is a NSString a message to description is not necessarily sent and that is why you are not getting an exception for attempting to message a deallocated object.
This question has some good information about NSString and NSLog.
When you do:
NSString * str = [[NSString alloc] initWithString:#"test"];
This gets optimized into:
NSString * str = #"test";
You can't release a constant string, because it's hardcoded into the application binary.
Proof:
NSString *s = [NSString alloc];
NSLog(#"%p", s);
s = [s initWithString:#"foo"];
NSLog(#"%p", s);
s = #"foo";
NSLog(#"%p", s);
Logs:
2011-04-12 10:17:45.591 EmptyFoundation[6679:a0f] 0x100116370
2011-04-12 10:17:45.599 EmptyFoundation[6679:a0f] 0x100009270
2011-04-12 10:17:45.604 EmptyFoundation[6679:a0f] 0x100009270
You can see that the result of +alloc is different from the result of -initWithString:, and the result of -initWithString: is equivalent to the constant string. Basically, -initWithString: says "aha, i'm going to be an immutable string, and I'm being given an immutable string! I can just take a shortcut, destroy myself, and return the parameter, and everything will still work the same"
You're using a bad pointer in you NSLog(). You happen to be getting lucky in this case, but you should expect code like this to crash or fail in other ways.
There is no need to delete the memory block, this will use up an unneeded cycle.
The memory will be overridden when an new object is allocated an occupy that memory block.
I've got a rather large loop that gets a string, does something to it, than goes onto the next one. I was originally releasing it then reallocating it but thought that is a bit of waste of resources but can't figure out how to just clear it out to reuse it.
One way would be [myString setString: #""].
The selected solution will crash with the following error:
'Attempt to mutate immutable object with setString:'
This worked for me instead:
self.myString = [NSMutableString stringWithString:#""];
make sure you synthesize myString in your class.