Best way to initialise / clear a string variable cocoa - iphone

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];
}

Related

Usage of NSMutableString vs NSString?

I am confused between NSString and NSMutable string usage.
Suppose I have instance variables one and two declared in class like this:
NSString *one;
NSMutableString *two;
let us suppose I have created setters and getters of them using properties.
lets say I have changed my "two" string like these:
1. [two appendString:#"more string"];
2. two = #"string"
3. self.two = #"string"
Questions:
would 1st line release previous string and allocate new object and assign value to it.
if yes, then does that mean creating getters and setters are unnecessary in this case ? OR its unnecessary to create properties in NSMutablestring
In this case would the previous allocated string object released ?
Its for sure that first object would be released as we are calling setters here. is this code necessary or we can just use the code line 2 to assign string.
Now about NSString:
As can modify the string like this also :
one = [one stringByAppendingString:#" more string"];
self.one = [one stringByAppendingString:#" more string"];
Which is better using NSMutablestring or NSString ?
Sorry for long post, but I needed to understand these concepts.
For the first part of your question:
Almost definitely not. I expect the memory will be allocated dynamically, rather than released and reallocated.
If the previous answer is no, this is also, no.
The second and third options don't even work with the warning Incompatible pointer types assigning NSMutableString to NSString
I expect NSMutableString will be slightly more efficient in terms of memory as you are indicating early on that the program may need memory dynamically. NSString is likely to be allocated a single, suitably sized block of memory.
Your views of NSMutableString seem to be what the stringBy.. methods of NSString will do:
With NSString and its stringBy... methods, you are creating new objects, releasing the old one (if need be) and making the new object autorelease. (Take care if you are changing from non-autorelease to autorelease, you may have a release in your dealloc that isn't needed anymore)
NSString is a not mutable string object, which means, after initialization, you cannot change it, NSMutableString is mutable meaning you can append another string to it or other modifications.
when you do [two appendString:#"more string"], the pointer still pointed to the same location in memory and you don't have to worry about allocation or deallocation.
When you do two = #"string" , it means you make your string pointer pointed to a specific location in memory which contains static string with value "string" inside.
When you do self.two = #"string", you've already have a property named two declared. By using property in xcode, you don't have to worry about the memory since you've already specified in your property declaration. It is a nice tool xcode provide to you, and you should definitely use it whenever you can.
NSMutableString will save some memory as NSString objects are always constants. So reassigning a new value to an NSString variable will allocate new memory for the new string.
However, please note a few errors in your code. You will have to initialize the objects before sending messages to them:
// this won't work
NSString *one;
[one stringByAppendingString:#"more string"];
// nor this
NSMutableString *two;
[two appendString:#"more string"];
// first do this:
NSString *one = #"an initial string constant"; // or
NSString *one = [NSString string];
NSMutableString *two = [NSMutableString string];
NSString objects are immutable this means that when you "modify" a NSString you are in fact creating a new string and not modifying the old which is not very effective. With NSMutableString the string is kept in a buffer than can be modified.
So the simple rule is that if you need to modify the string in any way use a NSMutableString and if not NSString. You can also cast a NSMutableString to a NSString but not the other way around (then you need to make a copy)

Getting NSString from char * (Converting C's char-pointer)

I want to show the char * in the UITextField
What I tried:
char *data;
char *name=data+6;
txtName.text=[[NSString alloc] initWithCString:name encoding:NSUTF8StringEncoding];
but I am not getting the correct value.
To create an NSString from a const char *, simply use these methods:
Returns an autoreleased object:
/**
* Should be wrapped in `#autoreleasepool {...}`,
* somewhere not far in call-stack
* (as closer it's, the lower our memory usage).
*/
NSString *stringFromChar(const char *input) {
return [NSString stringWithUTF8String: input];
}
Whenever we return an object (maybe to Swift), we need to register into nearest #autoreleasepool block (by calling autorelease method to prevent memory-leak, according to ownership-rules), but ARC does that automatically for us.
But even with ARC disabled, we are NOT forced to call autorelease manually, like:
return [[NSString stringWithUTF8String: name] autorelease];
Generally, convenience factory methods (like stringWithUTF8String:), already call the autorelease method (or should if ARC disabled), because the class simply does not intend to own the instance.
Creates a retained object:
NSString *result = [[NSString alloc] initWithUTF8String: name];
// ... Do something with resulted object.
// NOTE: calling below is not required
// (If ARC enabled, and should cause compile error).
[result release];
Update 2021 about difference; With ARC enabled, these two methods are equivalent (i.e. ARC will auto-call autorelease method; always registering to nearest #autoreleasepool).
Reference.
If you are not getting the correct value, then something is wrong with the data. Add a few NSLog calls to see what the strings contain.
What do you expect? You have an uninitalized char*. Then you add 6 to the pointer, which is already undefined behaviour. Then you try to turn a pointer pointing to any old rubbish (and you have no idea where it is pointing) to an NSString*. Nothing good can come from this.
Define a char* pointing to an actual, real C string using ASCII or UTF-8 encoding. Then create an NSString like this:
char* cstring = "Try harder";
NSString* objcstring = #(cstring);
You can use [NSString stringWithUTF8String: data].

NSString stringWithFormat causing iPhone app to crash

When I construct a dynamic URL using NSString stringWithFormat and then use that value in my XML parser I get random crashes. However if I test it with a constant string it works fine...
This is my code for generating the string,
loginURL = [NSString stringWithFormat:#"%#%#",ScriptURLString,#"authenticate"];
Which results in,
http://edms.digistorm.com.au/test/index.php?s=&sc=D41D8CD98F00B204E9800998ECF8427E&m=authenticate
Then I use it in my XML parser,
XMLReturnData = [[NSMutableArray alloc] init];
xml = [[XMLParser alloc]
initWithXMLPath:loginURL
lookForElement:#"Authenticate"
setCallbackObject:self
withSelector:#selector(dataReady)
data:XMLReturnData
];
For some reason this is causing my app to crash. If I use a constant string like,
loginURL = #"http://edms.digistorm.com.au/test/index.php?s=&sc=D41D8CD98F00B204E9800998ECF8427E&m=authenticate";
it works fine...
loginURL is defined as NSString *loginURL; inside my header file for this view.
Any help or guidance would be much appreciated!
Thanks,
Tim
The method you are using to allocate the string is important.
You have two basic ways to allocate your string:
NSString *loginURL = [[NSString alloc] initWithFormat:#"%#authenticate", ScriptURLString];
Compared to:
NSString *loginURL = [NSString stringWithFormat:#"%#authenticate", ScriptURLString];
For the first, Cocoa conventions say that because you caused the object to be created via an alloc message you "own" it and are responsible for releasing it.
For the latter, the convention is that because you caused the object to be created by a class "convenience" method, you do NOT own it and are not responsible for releasing it. The class (here, NSString) has that responsibility which it will discharge through an autorelease pool.
To summarise, when you explicitly create something with an alloc/init, you must release it. When you use a [NSThing thingWithXXX] style method you must not.
This shows your string is get released and when you calls it in XML parser it crashes the app.
actually stringWithFormat gives a autorelease object for string.
So what you need,make your string as retain property inside .h then synthesize it in .m and release it in dealloc method.
and also do this,
in viewDidLoad
NSString *tempString=[[NSString alloc] init]; //using this because your string is retain type so it prevent increment in retain count.
self.loginURL=tempString;
[tempString release];
Now when you use stringWithFormat use like this
self.loginURL = [[NSString stringWithFormat:#"%#%#",ScriptURLString,#"authenticate"] retain];
It solves your problem.
Not to call release on loginURL, because you have'nt alloced it and only iOS have right to destroy it...
Use below code
loginURL = [[NSString alloc] initWithFormat:#"%#%#",ScriptURLString,#"authenticate"];
Once you used loginURL Do'nt forget to call release on it ...
[loginURL release];
Try this, it might help you.
loginURL = [NSString stringWithFormat:#"%#authenticate",ScriptURLString];

Potential Leaked Object Error

I'm getting a potentially leaked object error from the Static Analyzer for this line:
strCleanPhone = [[[[strPhone stringByReplacingOccurrencesOfString:#" " withString:#""]
stringByReplacingOccurrencesOfString:#"(" withString:#""]
stringByReplacingOccurrencesOfString:#")" withString:#""]
stringByReplacingOccurrencesOfString:#"-" withString:#""];
For one, is this the preferred way to strip non-numeric characters from a phone number string?
Two, can you possibly explain why this would be a leaked object?
The strings created by stringByReplacingOccurrencesOfString are autoreleased, so they aren't leaked. If there's a leak, it has to do with strPhone and strCleanPhone.
For example, if strCleanPhone is a #property with the retain option, and is currently not nil, then your code leaks it. To use the release/retain code that was generated by synthesize you have to use the property syntax: self.strCleanPhone = .... Using just strCleanPhone = ... sets the instance variable and doesn't release any object it was pointing to.
If you're on iOS 4.0+, you might be able to use the new NSRegularExpression object to do this a little more elegantly.
The code you have as posted doesn't leak. It just creates four autoreleased string objects.
If you are looking to strip out characters that are not numbers.
NSString *strPhone = #"(555) 444-3333";
NSMutableString *strCleanPhone = [NSMutableString string];
for (int i=0;i<[str length];i++)
{
unichar ch = [str characterAtIndex:i];
if (isnumber(ch)) [strCleanPhone appendFormat:#"%c", ch];
}
But I suggest looking into regular expressions.
Make sure you expand the analyzer warning by clicking the warning text in the source view! Chances are it's pointing to where a variable is last referenced; if you expand the warning you'll see a bunch of arrows indicating code flow, which will help indicate where you've allocated your potentially-leaked object.
(tl;dr: Post more code.)

NSString *string = #"someString" vs NSString *string = [[NSString alloc] initWithFormat#"%#", string]

If I have a method
- (void) myMethod:(NSString *)string {
[Object anothermethodWithString:string];
}
and I call
[Object myMethod:#"this is a string with no alloc statement"]
Do I need to do something like
- (void) myMethod:(NSString *)string {
NSString *string2 = [[NSString alloc] initWithFormat:#"%#", string];
[Object anothermethodWithString:string2];
[string2 release];
}
instead of the way I had myMethod before? I have misbehaving code that seems to be caused by a string being auto-released while a second method within another method is being called (like in the example). The second way I have myMethod fixed all of my problems.
So is a "non-alloc" string an auto-released string? I asked this question as a follow up to another question (which was completely unrelated and is why I am creating this post), and a few sources said that I don't need to reallocate the string. I am confused, because the behavior of my code tells me otherwise.
Dave's got it right. You only need to worry about calling release on objects that you new, alloc, retain, or copy.
The above rule works very well, but if you're curious and want to get into a lot of detail, I suggest reading the Memory management Programming Guide from Apple's docs. It's free and goes from basic concepts into a lot of details.
If you use : NSString *str = #"". It is kind of a constant, you don't need to do any memory management.
If you call from a method : NSString *str = [NSString stringWithFormat:#""], the str is already autoreleased.
If you manually alloc, init. You need to call release, or autorelease yourself.
The general memory convention is : if you do something with new, alloc, retain, or copy, you need to release it yourself, any other cases, the object is autoreleased, don't release it