NSXMLParser throwing EXC_BAD_ACCESS - iphone

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.

Related

EXC_BAD_ACCESS error when switching back and forth between tableviews

A brief over view of what I am trying to do.
I am using the tableView:didSelectRowAtIndexPath: method inside my UITableViewController subclass which is catching a row selection from that view like so...
//..... inside tableView:didSelectRowAtIndexPath:
if (indexPath.section == 0) {
//--- Get the subview ready for use
VehicleSearchResponseTableViewController *vehicleSearchResponseTableViewController = [[VehicleSearchResponseTableViewController alloc] initWithNibName:#"VehicleSearchResponseTableViewController" bundle:nil];
// ...
//--- Sets the back button for the new view that loads
self.navigationItem.backBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:#"Back" style: UIBarButtonItemStyleBordered target:nil action:nil] autorelease];
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:vehicleSearchResponseTableViewController animated:YES];
if(indexPath.row == 0) {
vehicleSearchResponseTableViewController.title = #"Mans";
EngineRequests *engineRequest = [[EngineRequests alloc] init];
[engineRequest getMans];
[engineRequest release];
}
if(indexPath.row == 1) {
//.... etc etc
As you can see in this method I set up a few things, pushing the new view onto the viewstack and changing the back buttons text, then I go into catching the different rows and then initiating a method in a subclass of nsobject where I want to have all my connection/request stuff going on.
Inside my NSObject I have several different methods for the different cells that you can select on the UITableViewController, basicly they specify different strings that will then initialize my ASIHTTPRequest wrapper to make a connection to the php script and catch all the data that will come back from the database.. NSObject looks like this.
//.... NSObject.m
- (IBAction) getMans
{
NSString *mansString = [[NSString alloc] initWithString:#"mans.php"];
[self grabURLInBackground:mansString];
[manusString release];
}
//....cont....
//--- Connect to server and send request ---------------->>
- (IBAction)grabURLInBackground:(NSString *)setUrlString
{
NSString *startURL = [NSString stringWithFormat:#"http://127.0.0.1:8888/CodeTest/%#", setUrlString];
NSURL *url = [NSURL URLWithString:startURL];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSString *responseString = [request responseString]; //Pass request text from server over to NSString
NSData *responseData = [responseString dataUsingEncoding:NSUTF8StringEncoding]; //Create NSData object for Parser Delegate and load with responseString
NSLog(#"stuff %#",responseData);
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
NSLog(#"%#", error);
}
From here I would like to pass the data I am getting from the requestFinished method back over to the newly pushed UITableView.. However I have an error before I am able to get this far that I need to solve... if I run the simulator and click back and forth between the views (the main UITableViewController with the cells and then the newly popped view where I want to put the data) the application falls over and pops up an error in main.m Thread 1: program receive signal EXC_BAD_ACCESS.. I just don;t know whats causing because from what I can tell my code is not so bad.
Also when I debug my application I notice that once grabURLInBackground method has finished it bounces out back to the getMans method then goes back over to the UITableViewController and continues through the if statements, completely neglecting the requestFinished and requestFailed methods, and I just cannot figure out why.
I guess I am not sure if I am calling the methods and functions I need to use in the right places so if you have any suggestions or answers on how I can improve or if you know where my error is coming form that would be greatly appreciated.
There's a few issues with the code above but I'd guess that your bad access exception is due to the handling of your EngineRequests and use of AsiHttpRequest.
The code here
EngineRequests *engineRequest = [[EngineRequests alloc] init];
[engineRequest getMans];
[engineRequest release];
effectively creates an object then deallocates as soon as getMans has finished running.
Then inside the engineRequest object this code
[request setDelegate:self];
[request startAsynchronous];
requests that AsiHttpRequest notify the almost certainly released object once the request has completed.
There may be other issues at work here but I'd start by restructuring to try to keep this object around until at least after it's received the response from AsiHttpRequest.
Hard to tell from the brief overview, but generally when you bad_access and end up in the main application method, it's usually because you autoreleased something, then released it, and it craps out when the autorelease pool is drained. Might want to turn on NSZombiesEnabled and look for memory problems.
Who does receive your request?
The sender (and receiver) object is engineRequest.
But you release Engine Request in that very moment after you issued the async request (by mens of the getMans Method.
I would suggest that you
1. move the code
vehicleSearchResponseTableViewController.title = #"Mans";
EngineRequests *engineRequest = [[EngineRequests alloc] init];
[engineRequest getMans];
[engineRequest release];
from your UITableViewController's didSelectRowAtIndexPath method to your vehicleSearchResponseTableViewController's viewDidLoad method.
2. to retain your EngineRequests object and keep it in some instance variable within vehicleSearchResponseTableViewControllerand do not release it before the request is completely processed, either successfully or in error.

XMLParser leak instrument leak

NSURL *url = [[NSURL alloc] initWithString:#"http://www.someurl.com/sample.xml"];
xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[url release];
XMLParser *parser = [[XMLParser alloc] initXMLParser]; //50.0%
[xmlParser setDelegate:parser];
parser = nil;
[parser release];
[xmlParser parse]; //50.0%
[xmlParser release];
This is my parsing code and the leaks instrument is showing leaks. I really dont know what's wrong or how to fix this. Any suggestions?
parser = nil;
[parser release];
...this does not do what you think it does. Assuming parser is a property, then self.parser = nil and parser = nil do very different things. The former will call the parser setter method, which will release the old value and set the property to nil. The latter just changes the pointer from its current location to nil.
By setting the pointer to nil you have lost the reference to the object, so you've instantly leaked the object that was previous assigned to it - you are basically trying to release a nil object. You need to remove the nil call, or place it after the release (see below).
You may be thinking of setting a pointer to nil after you have released it, to prevent problems should you try and access it at some point in the future.
Here are a few other questions to help provide some context:
release Vs nil -- Best Practice
Difference between release and release then set to nil
I have had similar issues with using NSXMLParser, but found an easy fix to resolve the memory leak.
Instead of doing
xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
Do the following
NSData *xmlData = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
xmlParser = [[NSXMLParser alloc] initWithData:xmlData];
I was able to get rid of my memory leaks
There's a similar post here about leaks in the parser. I also have this issue. it's annoying but it's not a huge leak so I don't worry too much about it. Will see if iOS 5 fixed the problem (if it is indeed a known leak)
Edit: I'm now interested to see if I made the mistake above!

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

iPhone - Threading and Delegation

I'm running some code in a background thread to get a text file from a service. That code fires a delegate at some point. It throws as SIGABRT error once the delegate is being called and well, my concept doesn't sound convincing to me either.
The code running at the background thread:
- (void)FetchStores
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Fetch from service
NSString *serviceURL = #"http://../index.html";
NSURL *myURL = [NSURL URLWithString:serviceURL];
NSData *dataRep = [NSData dataWithContentsOfURL:myURL];
storesList = [[Stores alloc] init];
storesList.storesDelegate = self;
[storesList FetchWithNSData:dataRep];
[pool release];
}
The storesList object will fire a delegate once all the stores have been extracted from the service. The delegate is getting caught by a function at the main thread.
Do you have any suggestions what am I doing wrong ?
Thank you,
f.
When calling the delegate, somewhere, you should make the switch to the main thread.
Especially if somewhere, you are updating the UI based on the data fetched.
You can use
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait
to make the switch.
Maybe like this:
storesList = [[Stores alloc] init];
storesList.storesDelegate = self;
[storesList performSelectorOnMainThread:#selector(FetchWithNSData:) withObject:dataRep waitUntilDone:TRUE];
In your case, you should use waitUntilDone:TRUE so that the FetchWithNSData method gets a chance to retain the data.
It seems quite likely that FetchWithNSData: does not retain the passed dataRep and the data gets deallocated on the next line where you drain the local autorelease pool?

NSThread crashes on second call (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.