NSThread crashes on second call (iPhone) - iphone

I have an object and in that object I start my thread (for loading doing some URL loading).
When I have a return of my data I call a selector to perform on the main thread.
Works fine if I call it the first time, but the second time it crashes (no specific error).
[NSThread detachNewThreadSelector:#selector(doThread:)
toTarget:self
withObject:#"lala"];
-(void) doThread:(NSString *)poststring {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
DataModelLocator *mydelegate = [DataModelLocator instance];
NSData *postData = [poststring dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:NO];
NSURL *url = [NSURL URLWithString:[mydelegate fwaservicepath]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"content-type"];
[request setHTTPBody:postData];
NSURLResponse *urlResponse;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:nil];
if(data) {
[self performSelectorOnMainThread:#selector(loadDidFinishWithData:)
withObject:data
waitUntilDone:YES];
//[self loadDidFinishWithData:data];
} else {
[self performSelectorOnMainThread:#selector(loadDidFinishWithError:)
withObject:data
waitUntilDone:YES];
}
[pool release];
}
}
It crashes when I call performSelectorOnMaintThread... Could it be that it crashes on a singleton, when it got released?

When dealing with threads, avoid autoreleased objects like the plague. The autorelease pools will be drained at nondeterministic times, causing fun crashes. Use alloc/init and release on all objects involved, making sure to retain all objects that you take in on methods that are called from another thread using performSelectorOnMainThread or detachNewThreadSelector.
Garbage collection on the Mac effectively solves these problems, but the iPhone is not going to have that any time soon.

You may want to post some more information about your problem (which of the two lines crashes, what you've figured out from debugging so far, etc.) so that we can offer you some better suggestions. Without knowing which line is giving you problems, I'll hazard a guess: from the sound of it, you might have an object somewhere that's getting cleaned up by the automatic garbage collection.
Where is the variable "data" coming from? If you're creating it in the header file as a private member variable, you might have something like:
NSSomeType *data = [NSSomeType builtInInitFunction];
A variable initialized like this will normally be autoreleased, but you probably want to make sure that the garbage collection retains the instance of that object. Try something like:
// Objects initialized with init are retained
NSSomeType *data = [[NSSomeType alloc] init];
// Objects that would normally be autoreleased can be marked as retain
NSSomeType *data = [[NSSomeType builtInInitFunction] retain];
I'm not sure how your code is structured, but be sure to add at least one release for every retain and init! I'm still pretty new to Objective-C, so it's a little bit like the blind leading the blind so take my advice with a grain of salt.
Check out the "More on Memory Management" section of Learn Objective-C for more info.
EDIT2: Clarified example code. Thanks to Evan (comments) for the help.
EDIT3: I agree with Brad. Consider removing the AutoRelease pool you have an handling your alloc/init/release yourself. I don't know enough about the NSURLConnection object to know this, but is your *data memory being marked as Autorelease? If so, you may need to initialize in a different way or use retain.
Step through your code in the debugger. Figure out A) exactly which line is crashing and then B) the values of all of your variables. If you're lucky, you'll notice one is nil.

Related

How refresh UIVIewController to NSOperationQueue

I have a view where I show an UIImageView which complimentary internet, I use to bring data NSXMLparser which are loaded correctly, the problem was that I use to make the parser NSOperationQueue background so then I refresh the image in my main view. image which form no refresh them in any way
I leave here the code below
- (void)viewDidLoad
{
[Base64 initialize];
[super viewDidLoad];
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:#selector(loadDataWithOperation)
object:nil];
[queue addOperation:operation];
[operation release];
}
- (void) loadDataWithOperation {
getData=NO;
NSURL *url1 = [ NSURL URLWithString:[url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSData *xmlData = [NSData dataWithContentsOfURL:url1];
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:xmlData];
[parser setDelegate:self];
[parser parse];
[self performSelectorOnMainThread:#selector(showImage)withObject:nil waitUntilDone:NO];
}
-(void)showImage
{
NSArray *imagen =[[NSArray alloc] initWithArray:xml];
NSString *hola1 =[[imagen objectAtIndex:5]objectForKey:#"imagen"];
NSData * dataa = [Base64 decode:hola1];
img = [UIImage imageWithData:dataa];
self.images.image = img;
[images setImage:img];
[img release];
}
What am I doing wrong? appreciate your help please
I don't see anything obvious (though obviously we don't see the building of the xml array nor do we know precisely what the XML itself looks like). You should NSLog (or set a breakpoint and manually inspect) the xml as well as hola1 and dataa results in showImage, to identify at precisely what's going on at each step.
There are two possible problems with background operations and downloading XML. Neither of these seem applicable here, but I'll mention it just in case:
But there's nothing that would prevent the downloading and parsing of your XML like you have demonstrated here. If you were using NSURLConnection to download the XML (perhaps you simplified it here for the purposes of demonstration), there are issues in using NSURLConnection in a background queue. But if you use dataWithContentsOfURL (or better, NSXMLParser method initWithContentsOfURL) that wouldn't be an issue.
It looks like you're downloading a single XML, but if you were downloading multiple XML sources simultaneously, you should appreciate that many servers impose a limit as to how many concurrent connections they'll allow from a single client. You can use NSOperationQueue property maxConcurrentOperationCount to mitigate that problem. Four is a typical value.
Unrelated, but there are a couple of minor memory management things you might want to look at:
if you already have xml you don't need to create a new imagen;
you should probably release the queue object after adding the operation, or if you need to keep it around to reuse it, you should make it a class property or instance variable;
you could get rid of operation completely if you did:
[queue addOperationWithBlock:^{
[self loadDataWithOperation];
}];
you should release the parser object when you're done with it;
if you keep imagen in your code you should also release it when done; and
you should not release the img object since imageWithData returns an autorelease object
The routine memory management stuff probably would be pointed out to you if you did a static analysis (choose "Analyze" from the "Product" menu).
One final observation:
I notice that you have:
NSData *xmlData = [NSData dataWithContentsOfURL:url1];
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:xmlData];
Clearly that xmlData is not necessary because you could have also just have done:
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url1];

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

Cocoa - `stringWithContentsOfURL/dataWithContentsOfURL` causes ERROR?

The following code for some reason poradically works. I have checked the URL so many times it's not funny (It returns plain text that I would like to parse). The code was 100% functional then it just stopped working and started giving me a EXC_BAD_ACCESS error.
There is nothing in the debugging output to post other than a line saying the output is switching to the process twice. (Except sometimes something about a double release.)
So far (as much as I can remember) I have tried:
Reinstalling the app - it only has problems on the 'Default' run (not the first Run/initiate Run.)
Running the URL in the browser (chrome, firefox, IE...)
Putting the call in a #try / #catch block
Using retain
Using a temp NSAutoreleasePool
Splitting up / separating the elements of the call (along with loggin Everything - once it hits the error, nothing gets logged)
Using the dataWithContentsOfURL functions with the above
NSAutoreleasePool *tmpPool = [[NSAutoreleasePool alloc] init];
NSString *url_string = [self getNormalVersionDownloadURL];
NSLog(#"urlString: -%#-", url_string);
NSError *er;
NSURL *the_URL = [[NSURL URLWithString:url_string] retain];
NSString *version_String = [NSString stringWithContentsOfURL:the_URL encoding:NSASCIIStringEncoding error:&er];
NSLog(#"verions_string: -%#-", version_String);
if ([version_String length] < 16)
return;
[tmpPool release];
(NSAutoreleasePool and autorelease added due to http://discussions.apple.com/thread.jspa?threadID=1667544)
(Cashed page - http://webcache.googleusercontent.com/search?q=cache:8D7zlQdG9PMJ:discussions.apple.com/thread.jspa%3FthreadID%3D1667544+http://discussions.apple.com/thread.jspa%3FthreadID%3D1667544&cd=1&hl=en&ct=clnk&gl=us&source=www.google.com)
discussions.apple.com is currently down so I cannot read the discussion thread. At any rate:
NSString *url_string = [[self getNormalVersionDownloadURL] autorelease];
Does -getNormalVersionDownloadURL return an owned or a non-owned object? You only send -autorelease if the method returns an owned object.
NSError **er;
This should be NSError *er instead, or it should be initialised with the address of a variable of type NSError *. Since the latter is uncommon and unnecessary, the following assumes NSError *er.
NSURL *the_URL = [[NSURL URLWithString:url_string] autorelease];
+URLWithString: returns an NSURL object that you don’t own, hence you don’t (auto)release it.
version_String = [[NSString stringWithContentsOfURL:the_URL
encoding:NSASCIIStringEncoding error:er] autorelease]; //ERROR occurs here
Two problems:: +stringWithContentsOfURL: returns an NSString object that you don’t own, hence you don’t (auto)release it. Furthermore, the third parameter should be &er instead of er.
URLWithString and stringWithContentsOfURL are convenience methods and then already put the variable in autorelease I don't think you need to add autorelease while creating the_URL and version_String
try to remove autorelease ...

NSXMLParser throwing EXC_BAD_ACCESS

It is normal to have such issues but I am currently stuck in knowing how it works.
Whenever I use NSXMLparser to parse the URL and store in the database, it gets parsed for the first time but when I parse it again it throws EXC_BAD_ACCESS.
Here is my code:
- (void) initParse {
[super init];
appleAppDelegate = (appleAppDelegate*)[[UIApplication sharedApplication] delegate];
NSURL *url = [[[NSURL alloc] initWithString:#"http:example.com/file.xml"] autorelease];
self.parser1 = [[[NSXMLParser alloc] initWithContentsOfURL:url] autorelease] ;
[parser1 setShouldResolveExternalEntities:NO];
[parser1 setDelegate:self];
[parser1 parse];
}
When it reaches the end of the function at "}", it throws EXC_BAD_ACCESS. I am not sure what is wrong since I am releasing my URL and even my parser.
Has any one come across this situation.
Sagos
Try running with NSZombieEnabled - that will tell you the type of the object which is being accessed after being freed.
You are accessing a released object which is exactly your problem, make sure you release at the end and make sure everything you need is still around.

How do I reliably release memory in iPhone app?

If I have this code
NSString *postData = [#"foo=" stringByAppendingString:fooText.text];
...
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
...
[postData release]; //this causes crash
[request release]; //this causes crash
Now I understand this is the expected behavior according to Apple's documents. Now if i remove the release code the crash doesn't happen but I find that the memory leaks anyway for *request. So I rewrite the code
NSString *postData;
//postData = [NSString alloc]; // this line commented out since OP
postData = [#"foo=" stringByAppendingString:fooText.text];
...
NSMutableURLRequest *request;
request = [NSMutableURLRequest alloc];
request = [request initWithURL:url];
...
[postData release]; //this still crashes #
[request release]; //this works fine
I don't really understand why it would crash at # . Is there any recommended best practice here? I think I must be missing something because I often see the 'shorthand' approach (top) having a release (Kochan, Programming in Objective-C for example), but the Apple docs say that it's wrong.
The general rule of thumb, if you are calling a helper static method (such as stringByAppendingString), then you shouldn't release it. That string was added to an autorelease pool before being given to you. If you are calling alloc then an init... method, then you are responsible for releasing that object.
Other things to note in your code:
In the second example, you alloc postData, then immediately replace it with another string created by stringByAppendingString, that is a memory leak.
Your release calls are wrong, they should be [postData release] and [request release]
I don't see any correlation between postData and request in your example, so not sure exactly what you are getting at with the two of them.
First, in your second example, the line postData = [NSString alloc]; is completely unnecessary - postData is overwritten by the next line. Second, to answer your question as to why things crash - there is no good answer - the system can choose to free up memory anytime after the retain count hits 0. To more easily debug the issue, you should turn on NSZombieEnabled, which will immediately scribble any objects which are deallocated, giving you a 100% reliable way to test crashes.
Also, it is bad style to alloc/init on separate lines.
In general, you should focus on following the memory guidelines. If you're not following the guidelines, behavior can be undefined.
Allocating memory for your object and initializing it better perform in single line - init method may return different object and also it may help to avoid mistake you've made in 2nd example:
NSString *postData; // Define pointer to string
postData = [NSString alloc]; // Allocating nsstring pointer and assign it to variable
postData = [#"foo=" stringByAppendingString:fooText.text]; // assign to postData new **autoreleased** string object. result of the previous assignment is abandoned.
[postData release]; //so here you release autoreleased object!!
I cannot figure out why [equest release]; causes crash in the 1st example though.
P.S. I'm not completely wake up or it should be [postData release] instead of [release postData] ?
NSString *postData;
postData = [[NSString alloc]init];
postData = [#"foo=" stringByAppendingString:fooText.text];
...
NSMutableURLRequest *request;
request = [[NSMutableURLRequest alloc]initWithURL:url];
...
[postData release];
[request release];
Try this.