NSString stringWithFormat causing iPhone app to crash - iphone

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

Related

retainCount shows MaxInt

After trying to print retainCount of object I get 2147483647. Why do I get such a result? It should be 1, shouldn't?
NSString *myStr = [NSString new];
NSUInteger retCount = [myStr retainCount];
NSLog(#"refCount = %u", retCount);
2011-09-08 17:59:18.759 Test[51972:207] refCount = 2147483647
I use XCode Version 4.1. Tried compilers GCC 4.2 and LLVM GCC 4.2 - the same result.
Garbage Collection option was set to unsupported.
NSString is somewhat special when it comes to memory management. String literals (something like #"foo") are effectively singletons, every string with the same content is the same object because it can't be modified anyway. As [NSString new] always creates an empty string that cannot be modified, you'll always get the same instance which cannot be released (thus the high retainCount).
Try this snippet:
NSString *string1 = [NSString new];
NSString *string2 = [NSString new];
NSLog(#"Memory address of string1: %p", string1);
NSLog(#"Memory address of string2: %p", string2);
You'll see that both strings have the same memory address and are therefore the same object.
This doesn't directly answer your question, but retainCount is not really all that useful and should not be used for testing. See this SO post for details.
When to use -retainCount?
While NSString's are an odd case (there are others in the framework) you might also run across this in other clases - it's one of the ways of creating a singleton object.
A singleton only exists once in the app and it's pretty important that it never gets released! Therefore, it will overwrite some methods of NSObject including (but not limited to):
- (id)release {
// Ignore the release!
return self;
}
- (NSUInteger)retainCount {
// We are never going to be released
return UINT_MAX;
}
This object can never be released and tells the framework that it's a singleton by having a ludicrously high retain count.
Checkout this link for more information about singleton objects.
I've seen this a couple of times regarding NSStrings, the retainCount returns the maximum count instead of the actual one when you try to look at retainCounts of strings in this manner.
Try this;
NSString *myStr = [[NSString alloc] init];
NSUInteger retCount = [myStr retainCount];
NSLog(#"refCount = %u", retCount);
Edit: Restored NSUInteger

iOS: understanding Problem with release an NSString

I have following code:
+ (NSDictionary*) JSONRequest: (NSString*)query andWithCredentials:(BOOL)withCredentials
{
if (withCredentials)
{
NSString *username = [LoginHandler GetUsernameFromNSDefaults];
NSString *password = [LoginHandler GetPasswordFromNSDefaults];
NSString *additionalQuery = [NSString stringWithFormat:#"login_username=%#&login_password=%#", username, password];
query = [NSString stringWithFormat:#"%#&%#", query, additionalQuery];
[username release];
[password release];
[additionalQuery release];
}
NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:query]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *jsonString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSDictionary *results = [jsonString JSONValue];
return results;
[request release];
[response release];
[jsonString release];
[results release];
}
The problem is the Release of the additionalQuery-NSString.
When I run this code, it ends with an BAD-ACCES-EXCEPTION for the
[additionalQuery release];
As soon as I comment this out, the code works fine.
Now, as simple as it is, run my app without this line of code could be fine, but my question is: What do Im wrong?
I generate an NSString in an IF-Clause, then I CAN only release it in the IF-Clause. But why I got a Error there?
Look at your creation of additionalQuery
NSString *additionalQuery = [NSString stringWithFormat:#"login_username=%#&login_password=%#", username, password];
With stringWithFormat you create an autoreleased NSString object. You MUST NOT release it manually according to the Memory Management rules since you don't own it.
You own only things you created with alloc] init..] or something with new.. or create.. in the name and of course if you do a copy such as mutableCopy.
So [additionalQuery release] causes over-releasing an object and thus it is a BAD ACCESS
The problem is that the string instance is created using a class method that starts with the class name (stringWithFormat). By convention, these types of class methods return an autoreleased object, freeing you from worrying about releasing them unless you specifically call retain on the returned object.
If you do want to perform your own memory management on the object, you could change your line:
NSString *additionalQuery = [NSString stringWithFormat:
#"login_username=%#&login_password=%#", username, password];
to either of the following:
NSString *additionalQuery = [[NSString alloc] initWithFormat:
#"login_username=%#&login_password=%#", username, password];
or:
NSString *additionalQuery = [[NSString stringWithFormat:
#"login_username=%#&login_password=%#", username, password] retain];
As an aside, you also have several other issues with this code.
The username variable should not be released because again, by convention, the method you get it from GetUsernameFromNSDefaults should return an autoreleased object. As a general rule of thumb, any method other than an init method should return an autoreleased object. It would become very difficult for a programmer not knowledgable with the codebase to pick it up and modify without following these conventions.
The request variable does not need to be released because it is created with a class method that returns an autoreleased object (requestWithURL). If you wanted it to be retained by your code, either call retain on it, or use the method initWithURL:.
Additionally, the results variable is not retained by you, so there is no need to release it.
You don't have to release it manually, it will get autoreleased. ([NSString stringWithFormat:] vs. [NSString initWithString:])
additionalQuery was never retained, that I can see. (stringWithFormat does an autorelease, so it doesn't count.)
When you create an instance of an object using a convenience method (one that does not begin with new, alloc or copy) the returned object is autoreleased. In other words you do not need to explicitly release it.
When you invoke the stringWithFormat method it returns an autoreleased NSString. You subsequently go on to release this NSString instance...
[additionalQuery release];
This sends the release message to the additionalQuery instance. As it's an autoreleased object it is added to an autorelease pool which lives (usually) on the main event thread. This pool is drained frequently and subsequently sends a release message to each of the objects it contains. Hence when an object is autoreleased the pool will look after sending the release message for you.
Your EXC_BAD_ACCESS here is a result of you releasing the NSString - dropping its retain count to 0 prior to the pool draining. The pool is then drained and attempts to send a message to a deallocated object.
you have specified here [NSString stringWithFormat:#"login_username=%#&login_password=%#", username, password];
means this method will handle allocation and release for your string so "you do not need to release it" hence remove the line [additionalQuery release];
also, u are not allocating string for username and password hence no need to release it .
if you write Nsstring *username = [[NSString alloc]init]; then you need to release it..
for more information regarding Memory Management refer
http://marcelsite.heroku.com/posts/5-iPhone-s-alloc-init-new-retain-release-autorelease-copy-
this will really help you...

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

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

iPhone Memory Management

I'm working on an app and I'd like to make sure that I'm managing memory properly and releasing everything that I should. In my viewDidLoad method I allocate some variables in determining which background to apply to the view (for internationalization) and the app works fine if I don't release them.
The problem is that if I release the variables the app will crash. Code from viewDidLoad is below:
// Set the background image based on the phone's preferred language
NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0];
NSString *backgroundImageName = [[NSString alloc] init];
backgroundImageName = [NSString stringWithFormat:#"background-%#.png",language];
self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:backgroundImageName]];
... do some more initialization stuff ...
// IF THE FOLLOWING ARE RELEASED THE APP WILL CRASH!!!
//[backgroundImageName release];
//[language release];
Why would releasing the backgroundImageName and language variables cause the app to crash?
NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0];
Here, language does not need to be released because objectAtIndex: autoreleases it for you. By convention, you own an object if you've alloced, newed, or copyed it, otherwise you don't.
self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:backgroundImageName]];
Here, the UIColor object does need to be released (because you alloced it).
NSString *backgroundImageName = [[NSString alloc] init];
backgroundImageName = [NSString stringWithFormat:#"background-%#.png",language];
Here the string returned by [[NSString alloc] init] does need to be released (because you've alloced it). However, the next line changes backgroundImageName to point to that a new autoreleased string, losing the last reference to the original string without releasing it (a memory leak). backgroundImageName should not be released because it is already autoreleased.
You can avoid the leaks by releasing the UIColor and eliminating the unused string. For example:
NSString *backgroundImageName = [NSString stringWithFormat:#"background-%#.png",language];
... and ...
UIColor* backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:backgroundImageName]];
self.view.backgroundColor = backgroundColor;
[backgroundColor release];
short answer :
when you create an object using constructors that dont have the word init then you are not responsible for releasing it
see this for more explanation
also the memory management guide is an excellent resource to know more about memory management in objective c
You're not creating the language string; you're just getting back a reference. Only methods that have "new", "copy", or "alloc" in them (by convention) return non-autoreleased objects. For all other methods, it's assumed that you'll discard the variable, so if you want to keep it around, you MUST retain it. The flip side of this is: you should not release these returned objects unless YOU retained them.
The other problem in this code is that backgroundImageName is being assigned twice. The first initialization is being lost. Get rid of it, and just keep the second one, and get rid of both -release calls, they're not needed.