I am getting the NSConcreteData leaked object while testing the leaks in the instruments.It showing in the parser,
- (void)parseXMLFileAtURL:(NSURL *)URL
{
[urlList release];
urlList = [[NSMutableArray alloc] init];
myParser = [[NSXMLParser alloc] initWithContentsOfURL:URL] ;// it showing this line as leaking
[myParser setDelegate:self];
[myParser setShouldProcessNamespaces:NO];
[myParser setShouldReportNamespacePrefixes:NO];
[myParser setShouldResolveExternalEntities:NO];
[myParser parse];
[myParser release];
}
That is extremely unlikely to be the source of the leak, since you're not using NSData around there, like, at all. You might want to see where that URL comes from.
Edit: It might be nice if you edit your original post with the new information, but nonetheless; insofar as I can see, that code shouldn't leak. This kind of error can be tedious to track down; and the NSConcreteData might be a red herring, but I'm thinking you should look for your uses of NSData throughout your project.
Related
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];
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!
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.
Anyone else experiencing crashes deep down in the iPhone libraries when NSXMLParser parses an xml containing errors? I thought it was supposed to call:
(void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
but instead it crashes the entire app somewhere inside _xmlRaiseError.
Is anyone else experiencing this and is there a way to catch this, instead of having my program crash?
The error handling is not found in the TouchXML framework or in the CXMLDocument. It is in the libxml framework which will (to my knowledge) output a string but not raise an exception. So it is all about passing an error pointer and then reading it straight after. If it is not nil, an error has occurred. If you are getting crashes the error should be somewhere else... Hope that helps.
You should be able to use #try/#catch to wrap this if you need to handle all kinds of malformed XML.
The XML parser never crashes for me, but my handlers have crashed on occasion. For example if I get < foo /> and try to store the value of it in an array (nil, boom). The following is the exact code I use, which parses XML using a delegate that I've made.
NSData *data = [[NSData alloc] initWithContentsOfFile:filename];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:data];
MGXMLParser *parser = [[MGXMLParser alloc] initWithRecipient:self];
[xmlParser setDelegate:parser];
BOOL success = [xmlParser parse];
if (success) {
NSLog(#"No errors");
} else {
NSError *error = [xmlParser parserError];
NSLog(#"Errors with xmlParser: %#", [error localizedDescription]);
}
[parser release];
[xmlParser release];
[data release];
MGXMLParser is my own class which is a delegate for the XML parser, in case it wasn't obvious.
Update: oops, SO parsed my < foo/ > into nothingness.
The problem is probably that your XML string gets autoreleased before parseErrorOccurred ever gets called, causing a call to a dealloc'd object.
The solution is do to something like:
NSData *data = [[contentString dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES] retain]; //use a retain, to stop data being autoreleased
NSXMLParser* xmlParse = [[NSXMLParser alloc] initWithData:data];
[xmlParse setDelegate:self];
[xmlParse parse];
[data release]; //now release data
[xmlParse release];
I filed this as a bug report and Apple answered me 1 year later to say it should be fixed in iOS5.
In my iPhone application, I have an instance of NSXMLParser that is set to a custom delegate to read the XML. This is then moved into its own thread so it can update the data in the background. However, ever since I have done this, it has been giving me a lot of _NSAutoreleaseNoPool warnings in the console. I have tried to add a NSAutoreleasePool to each of my delegate classes, however, this hasn't seemed to solve the problem. I have included my method of creating the NSXMLParser in case that is at fault.
NSURL *url = [[NSURL alloc] initWithString:#"http://www.mywebsite.com/xmlsource.xml"];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
CustomXMLParser *parser = [[CustomXMLParser alloc] init];
parser.managedObjectContext = self.managedObjectContext;
parser = [parser initXMLParser];
[xmlParser setDelegate:parser];
[NSThread detachNewThreadSelector:#selector(parse) toTarget:xmlParser withObject:nil];
If anyone has any ideas to get rid of this problem, I would really appreciate it.
Thanks.
In objective-c each thread needs its own NSAutorelease pool to handle autoreleased objects. So in your parse method you need to create (and release) NSAutoreleasePool object:
- (void)parse{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
...
// your method implementation
...
[pool release];
}