NSMutableString stringWithString giving crash - iphone

ten.textValue = [[NSMutableString alloc]init];
ten.textValue = [NSMutableString stringWithString:textField.text];
I am getting crash at second line.
ten.textValue is NSMutableString.

It is probably because the text property of UITextField is nil by default, and passing nil to [NSMutableString stringWithString:nil] causes a crash.
You need to make sure the text is not nil when you pass it to be copied, for example like this:
[NSMutableString stringWithString: textField.text ? textField.text : #""]
You should also eliminate the first line - it serves no purpose, because the allocated and assigned value gets overwritten immediately.

When you create your ten.textValue = [[NSMutableString alloc]init]; you are creating an object that you own.
When you try to add a string to it in the next line, you are creating an autoreleased string. This is confusing the compiler, which is reporting "hang on - this is an allocated, owned object already".
Instead:
if(ten.textValue)
{
ten.textValue = [NSMutableString stringWithString: textField.text]};
}

Related

Potential memory leak

I work on a project on iPhone iOS with Xcode 4.
With Xcode > Product >Analyze I get 35 issues, all of this type:
myTextField.text = [[NSString alloc] initWithFormat:#"0.2f", abc];
and the problem is "Potential leak of an object allocated at ..."
What is the offending object and how can I release it?
Thanks
You're leaking the string that you're assigning to myTextField.text. When this assignment happens, a copy is being made (look at the property definition in the documentation). In most cases, when values are immutable, as is the case with NSStrings, a copy will give you an instance that points to the same location as the object that is being copied, with the retain count incremented by 1.
In the case of your code:
myTextField.text = [[NSString alloc] initWithFormat:#"0.2f", abc];
The retain count of the string that you've allocated is 2.
You will either need to (1) release, (or autorelease) the string, or (2) use one of the NSString convenience methods, e.g. stringWithFormat: to create the string. This will give you an autoreleased string so you won't have to worry about explicitly releasing it.
(1)
NSString *str = [[NSString alloc] initWithFormat:#"0.2f", abc];
myTextField.text = str;
[str release]
or
myTextField.text = [[[NSString alloc] initWithFormat:#"0.2f", abc] autorelease];
(2)
myTextField.text = [NSString stringWithFormat:#"0.2f", abc]; // autoreleased
You are responsible for releasing string object you create here - as you use alloc/init for that.
The most convenient way here to set a string is to use class method +stringWithFormat that returns autoreleased string - so system will release that string object for you later:
myTextField.text = [NSString stringWithFormat:#"0.2f", abc];
Or you can write autorelease explicitly if you want:
myTextField.text = [[[NSString alloc] initWithFormat:#"0.2f", abc] autorelease];
If you don't want to use autorelease you can use temporary variable to create new string and release it after it was set for text field:
NSString *tempString = [[NSString alloc] initWithFormat:#"0.2f", abc];
myTextField.text = tempString;
[tempString release];
The thing is that UiTextFields's text property is declared as:
#property(nonatomic, copy) NSString *text
Therefore in this line:
myTextField.text = [[NSString alloc] initWithFormat:#"0.2f", abc];
A new NSString is created with a retain count of 1, and then myTextField.text copies this object and increased its retain count by 1 or does it??, lets see what is happening:
A NSString object created with alloc initWithFormat with a retain count of 1
A NSString object with is a copy of the previous String, but because NStrings are immutable in this case, copy returns the same object!, therefore the NSString actually has a retain count of 2.

Can't put a NSString into a NSMutableArray and store it in NSUserDefaults

I am receiving this error: '-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'
In the ViewDidLoad I initialized my array:
id object = [[NSUserDefaults standardUserDefaults] objectForKey:#"array"];
if (object)
{
locationArray = object;
NSLog(#"retrieved", object);
}
else
{
locationArray = [[NSMutableArray alloc] init];
NSLog(#"init");
}
Then, I am trying to add the data to locationArray:
ABMultiValueRef multi = ABRecordCopyValue(person, property);
NSUserDefaults *locatie = [NSUserDefaults standardUserDefaults];
// Set up an NSArray and copy the values in.
NSArray *theArray = [(id)ABMultiValueCopyArrayOfAllValues(multi) autorelease];
//everything goes fine the first time, but the second time i receive an error after at this code:
[locationArray addObject:theArray];
[locatie setObject:locationArray forKey:#"array"];
Every first time I select an address everything is fine. But every second time I am receiving that error.
What did I do wrong?
NSString *fname = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSMutableString *lname = (NSMutableString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
What makes you think ABRecordCopyValue is going to return a mutable string here?
Just telling the compiler that it will return a mutable string (which is all “(NSMutableString *)” does) doesn't mean it will. If the Address Book documentation doesn't specify that this will return a mutable string, assume it won't and create a mutable string yourself.
Speaking of which…
NSMutableString *name = [[NSMutableString alloc] init];
Here's the string you should be appending to. You don't need lname to be mutable, because this string is mutable.
NSMutableString *space = #" ";
fname = [fname stringByAppendingFormat:space];
fname = [fname stringByAppendingFormat:lname];
By doing this, you waste the mutable string you created. You are creating two intermediate immutable strings here, not appending to the mutable string.
name = fname;
And here, you throw away the mutable string entirely (and thereby leak it since you never released it), replacing it with the immutable string you got from your series of stringByAppendingFormat: messages.
What you should do is send the name mutable string an appendFormat: message, passing both the first and last name strings. You don't need the space string; you can include that in the format string.
See also the NSMutableString docs.
[nameArray addObject:fname];
At no point prior to this statement have you created an NSMutableArray object and stored its pointer in the nameArray variable. Not in any code you've shown, anyway.
Until you do that, this variable holds nil, the pointer to no object. The addObject: message does nothing because that's what messages to nil do: Nothing. Logging the array you don't have produces “(null)” because that's the description of nil.
if (nameArray == nil) {
NSLog(#"NO DATA TO RETRIEVE FROM USERDEFAULTS");
You aren't showing any code that retrieves from user defaults. Even if you did, it would return an immutable array as Sven said; you would have to make a mutable copy.
This is the best I can do without a description of the problem. We may be able to provide more and better suggestions if you edit your question to tell us what happens when you run the above code, and not just what doesn't happen.
The problem occures when you get the locationArray from the NSUserDefaults and try to insert some object ([locationArray addObject:theArray];). The object you get from the NSUserDefaults is not mutable, so you have to create a mutable copy:
NSMutableArray* locationArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"array"];
if (locationArray != nil)
locationArray = [[locationArray mutableCopy] autorelease];
else
locationArray = [NSMutableArray array];
And don't forget to check if fname is not nil before adding it to array

How to reset a NSMutableString with a empty value?

NSMutableString *str = [[NSMutableString alloc] init];
Suppose str has right know a value "me".
And On click of a button I want that the value of str get reset. That is the string value become nil or empty.
now i am using this [myword stringWithString: #""]; but not working.
Use setString with "" as parameter.
[myWord setString:#""];
And if you want to make it nil, then release it and then set it to nil.
[myWord release];
myWord = nil;

Best way to initialise / clear a string variable cocoa

I have a routine that parses text via a loop. At the end of each record I need to clear my string variables but I read that someString = #"" actually just points to a new string & causes a memory leak.
What is the best way to handle this? Should I rather use mutable string vars and use setString:#"" between iterations?
You have to be careful in which case you create the NSString: (factory method) or (alloc init or (using #"").
If you use #"", it is a constant string, see here: Constant NSString
If you use [[NSString alloc] init], you need to release it.You just need to do [someString release].
If you use something like [NSString stringWithFormat:#""], you don't need to release it because it is already auto released by runtime
Since NSStrings are immutable, you cannot change the contents of the string. And by initializing it with #"" you're actually creating a constant NSString object.
You can either work with a NSString local to the loop, and release it in the end of the loop - or you can use a NSMutableString instead. I would prefer the loop local string though.
for ( ; ;) {
NSString* str = [[NSString alloc] initWithFormat:#"%#", CONTENT];
...
[str release];
}

How to return correctly a NSMutableString from a method

I'm looking for a good way to return a string constructed by a NSMutableString avoiding leaking :
eg:
+(NSString *)myMethod{
NSMutableString *numberToReturn = [[NSMutableString alloc] init];
[numberToReturn appendString:#"lorem ipsum"];
return numberToReturn;
}
The leak instrument said I had leak with this variable.
I tried autorelease but it crashes
I tried to return a copy or copying the mutablestring into a nsstring but leak still present.
Any idea or trick?
I'have a to call this method each time the user type a value into the textfield, so the application crashes due to bad memory management...
thank you
You should use -autorelease. Your method should be written as:
+ (NSString*)myMethod {
NSMutableString *stringToReturn = [[NSMutableString alloc] init];
[stringToReturn appendString:#"lorem ipsum"];
return [stringToReturn autorelease];
}
If there is a crash, the fault is elsewhere.
Of course, you can make use of factory methods that return an already-autoreleased instance, rewritting your method as
+ (NSString*)myMethod {
NSMutableString *result = [NSMutableString string];
[result appendString:#"lorem ipsum"];
return result;
}
or better yet for your example,
+ (NSString*)myMethod {
NSMutableString *result = [NSMutableString stringWithString:#"lorem ipsum"];
//...do something with result;
return result;
}
Obviously if you method's only purpose is just to return a new string with a string, you can avoid the whole method all together and use [NSMutableString stringWithString:#"lorem ipsum"] if you really need a mutable string.
You should autorelease the string before returning it. That's what the memory management rules say to do. If your app then crashes, that's evidence of a bug somewhere else in your code.