Clearing rather than releasing a NSMutableString - iphone

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.

Related

Autoreleasing twice an object

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);

ObjctiveC yet another retain-copy-release error [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Objective C alloc/release error
When I try the code below it crashes with BAD_ACCESS if I release newString. What am I missing here?
As far as I know, when I use "copy" as an accessor I got the ownership of the object, so even should I release the other referencing pointer, retain count should still stay 1+, so that object should still be in memory?
P.S. This is a singleton class if it makes a difference.
.h file
NSString *originalString;
#property (nonatomic,copy) NSString *originalString;
.m file
#synthesize originalString;
...
NSString *newString = [[NSString alloc] init...];
self.originalString = newString;
[newString release]; //this lines makes it crash
I've also tried
self.originalString = [newString copy];
with no luck..
Have you tried using retain instead of copy?
http://wiki.cs.unh.edu/wiki/index.php/Objective_C_Property_Attributes#Setter_Semantics
I'm not really sure whether or not this would actually work if copying doesn't, but using retain instead of copy should cause the reference count to the string to increment by 1 when assigned to the property, bringing it up to 2 from the 1 it was when the string was alloced, so when you use [newString release]; on the line after the property assignment, the string should end up with reference count 1 and thus continue to exist.
[newString relase]; //this lines makes it crash
relase probably isn't the name of a method. Did you mean release?
Assuming the above was just a typographical error in your question, and not an error in your code, then your code is correct, and you'll need to provide more information about the error. Pasting the actual code of the method in question would be helpful in that case.
this code looks correct, are you sure the crash isn't somewhere else?
EDIT: as noted in the comments, NSString being immutable won't cause the copy to allocate a new object. I've edited the answer for the mutable case, just in case someone stumbles into this later and doesn't read the whole thing.
Now back with our regular programming.
Don't know if this might be the problem, but note that, if you were using a mutable object like NSMutableString, with copy you would not increment the retain count, you would effectively create a new object, so what would happen:
NSMutableString* newString = [[NSMutableString alloc] init..]; // allocate a new mutable string
self.originalString=newString; // this will create yet another string object
// so at this point you have 2 string objects.
[newString relase]; //this will in fact dealloc the first object
// so now you have a new object stored in originalString, but the object pointed
// to by newString is no longer in memory.
// if you try to use newString here instead of self.originalString,
// it can indeed crash.
// after you release something, it's a good idea to set it to nil to
// avoid that kind of thing
newString = nil;
Have you tried just adding autorelease to your *newString init? Then just take out the manual release all together.
NSString *newString = [[NSString alloc] init...] autorelease];
You may consider to migrate your codes to Xcode 4.1 with ARC, then you would not need to worry about retain and release of objects.

Obj-C, Memory leak confusion

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.)

NSString vs NSMutableString with stringByAppendingString

So, I'm fairly certain that if I plan on manipulating strings often, such as with stringByAppendingString, I should be using variables of type NSMutableString.
But what if I'm doing something like this?
UILabel *someLabel = [[UILabel alloc] init];
[someLabel setText: [[someDictionary objectForKey:#"some_key"] stringByAppendingString:#"some other string"];
I read that if you use stringByAppendingString on an NSString, you end up with leaks because the pointer associated with the initial NSString moves around, pointing to the new string created by the append, whereas with NSMutableString, your pointer always points to that mutable string.
So my question is, what is implicitly happening when I call stringByAppendingString on something that is a string, but not explicitly an NSString or an NSMutableString? Such as, in my above case, the value of some key in a dictionary. Is doing this wrong, and should I be doing something like below?
[[[NSMutableString stringWithString:[someDictionary objectForKey:#"some_key"]] stringByAppendingString:#"some other string"]]
I read that if you use
stringByAppendingString on an
NSString, you end up with leaks
because the pointer associated with
the initial NSString moves around,
pointing to the new string created by
the append, whereas with
NSMutableString, your pointer always
points to that mutable string.
That sounds like the advice of someone who didn't quite have a grasp of what is going on with the memory management. Sure, [NSString stringByAppendingString] returns a new string. But what you do with that new string is up to you. You could certainly cause a memory leak by reassigning the result to a retained property in a careless fashion, like so:
myStringProperty = [myStringProperty stringByAppendingString:#" more bits"];
The correct form would be to use self, like so:
self.myStringProperty = [myStringProperty stringByAppendingString:#" more bits"];
Follow the cocoa memory guidelines.
As for dictionaries and other collection types: treat what comes out of the dictionary appropriately given the type you know it to be. If you pull an object out which is actually an NSString, but try to use it as a NSMutableString, your app will fall over (with 'selector not found' or similar). So in that case, you do need to make a new NSMutableString from the NSString.
Interesting note: Apple chose to make NSMutableString a subclass of NSString. Something about that seems unwise to me -- if something looks to be immutable, because it has type NSString, I want it to be immutable! (But in fact it could be NSMutableString.) Compare that to Java, which has a String class and a completely separate BufferedString class.
I've always been a fan of [NSString stringWithFormat#"%#%#", a, b]; because then you clearly get a new autoreleased string and can dispose of "a" and "b" correctly.
With [someDictionary objectForKey:#"some_key"], you will be getting the type of object that was put into that dictionary originally. So blindly calling stringByAppendingString without knowledge of what's in that dictionary seems like a bad idea.
-stringByAppendingString is going to return you a new NSString that is distinct from both strings involved. In other words:
NSString *string3 = [string1 stringByAppendingString:string2];
string3 is an entirely new string. string1 isn't changed at all, nothing happens to its memory location or contents. The person who told you that probably just misunderstood what was going on.
[mutableString1 appendString:string2];
In this case, mutableString1 still points at the same object, but the contents of that object have been altered to include string2.
One last thing to keep in mind is that if you are using mutable strings, you should be careful with sharing references to it. If you pass your mutable string to some function which keeps a pointer to that mutable string and then your code changes that mutable string at some point in the future, the other reference is pointing at exactly the same object which means the other code will see the change as well. If that's what you want, great, but if not you must be careful.
One way to help avoid this problem is to declare your #property statements for NSStrings to be "copy" instead of "retain". That will make a copy of your mutable string before setting it in your property and the -copy method implicitly gives you a NON-mutable version, so it'll create an NSString copy of your NSMutableString.
If you follow the rules for memory management, you will be fine using stringByAppendingString. In a nutshell:
if you own an object, you need to release or autorelease it at some point.
you own an object if you use an alloc, new, or copy method to create it, or if you retain it.
Make sure you read up on Apple's Memory Management Rules.
In the first code sample in your question, you aren't using alloc, new, copy or retain on any of the NSStrings involved, so you don't need to do anything to release it. If outside of the code that you've included in the sample you are using alloc, new, copy or retain on any NSStrings, you would need to ensure that they are released later.

Sometimes NSString becomes Invalid?

In my own iPhone Application I have used a number of nsstring variables to store values. But sometimes its value becomes Invalid! Does anybody know what may be the reason? Or tell me about the situation when a nsstring variable becomes Invalid?
NSStrings are also objects. They go by the same memory management rules. If you sin against those rules you will get a pointer to invalid memory and it will look like "invalid" data.
For example:
myString = [NSString stringWithString:#"foo"];
This will create an NSString* that's got autorelease on. When you're assigning it to an ivar that autorelease pool will soon pop putting the retain count back to 0 and dealloc'ing it while you still have a reference to it!
Naughty.
Instead, either retain it or use:
myString = [[NSString alloc] initWithString:#""];
This returns an owning reference. Remember to [myString release]; in dealloc.
This is just one example/case of bad memory management. Read the docs on how to properly manage your object lifecycle. Really.
They are being autoreleased. If you create a string using a convenience method (stringWithString, stringWithFormat) it will be added to the autorelease pool.
To stop it being released automatically, sent it a retain message and a release message when you have finished using it so that the memory is released. You can also set up properties to do this semi automatically when you assign the string to a member variable
There are a lot of articles on iPhone (and Mac) memory management here on SO and on the interwebs. Google for autorelease.
If this is for a device with fairly limited resources such as the iPhone, you should use [[NSString alloc] init*] over the static convenience methods, as you will put less pressure on the autorelease pool and lower your memory usage. The pool is drained every message loop, so the less objects to enumerate the better.
You should also be aware that autorelease objects in a loop will generate a lot of garbage unless you manage a local autorelease pool.
did you copy or retain the NSString ?
I asked the same question. And the following answer was the best of convenience. Just use:
[myString retain];
And then in dealloc method (e.g. viewDidUnload):
[myString release];