iPhone XML Parser - [c setImage:[attributeDict objectForKey:#"img"]]; WARNING - iphone

Hi I am having issues with the following and it crashes the iPhone simulator, while the script has no errors it did bring up one warning in this script.
[c setImage:[attributeDict objectForKey:#"img"]];
The warning is
City may not respond to -setImage:
I am not sure what I have done wrong here is the fill source code.
#import "LocationsParser.h"
#implementation LocationsParser
#synthesize managedObjectContext;
-(id) initWithContext: (NSManagedObjectContext *) managedObjContext
{
self = [super init];
[self setManagedObjectContext:managedObjContext];
return self;
}
- (void)parseXMLFileAtURL:(NSURL *)URL parseError:(NSError **)error
{
// /Applications/MyExample.app/MyFile.xml
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:URL];
// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
[parser setDelegate:self];
// Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
NSError *parseError = [parser parserError];
if (parseError && error) {
*error = parseError;
}
[parser release];
}
-(void) emptyDataContext
{
// Get all counties, It's the top level object and the reference cascade deletion downward
NSMutableArray* mutableFetchResults = [CoreDataHelper getObjectsFromContext:#"County" :#"Name" :NO :managedObjectContext];
// Delete all Counties
for (int i = 0; i

use this
[c setImage:(id)[attributeDict objectForKey:#"img"]];

c - what is it? E.g., if it is supposed to be UIImageView, you can do so:
[(UIImageView *)c setImage:[attributeDict objectForKey:#"img"]];

Related

Memory Leaks when we are using NSXmlParser in auto Release pool

- (void)main
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
self.workingArray = [NSMutableArray array];
self.descriptionString = [NSMutableString string];
NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:dataToParse] autorelease];
[parser setDelegate:self];
[parser parse];
if (![self isCancelled])
{
// notify our AppDelegate that the parsing is complete
[self.delegate didFinishParsing:self.workingArray];
}
self.workingArray = nil;
self.descriptionString = nil;
self.dataToParse = nil;
[pool drain];
}
in this code when we [parser parse] is called in this line the memory leaks problem is happened.

Memory Leak In line of code

My app is working fine, but when I run instrument for checking for leaks, it shows me a leak at this line of code, in purple with a 100.0% mark:
xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
Here's the method containing this line:
-(NSString*) languageSelectedStringForKey:(NSString*) key
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"zh" ofType:#"lproj"];
if(selectedLanguage==French)
{
FinalString = [[NSString alloc] initWithFormat:#"http://www.xyz.com/api_com.php?page_id=%d",IDValue];
url = [[NSURL alloc] initWithString:FinalString];
}
else if(selectedLanguage==German)
{
FinalString = [[NSString alloc] initWithFormat:#"http://www.x.com/api_com.php?page_id=%d",IDValue];
url = [[NSURL alloc] initWithString:FinalString];
}
else if(selectedLanguage==Nepali)
{
FinalString = [[NSString alloc] initWithFormat:#"http://www.xy.com/api_com.php?page_id=%d",IDValue];
url = [[NSURL alloc] initWithString:FinalString];
}
xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[url release];
//Initialize the delegate.
parser = [[NewsParser alloc] initXMLParser];
//Set delegate
[xmlParser setDelegate:parser];
//Start parsing the XML file.
BOOL success = [xmlParser parse];
if(success)
NSLog(#"No Errors");
else
NSLog(#"Error Error Error!!!");
NSBundle* languageBundle = [NSBundle bundleWithPath:path];
NSString* str=[languageBundle localizedStringForKey:key value:#"" table:nil];
return str;
}
Here's my ViewDidLoad method from which languageSelectedStringForKey is called.
- (void)viewDidLoad
{
// Do any additional setup after loading the view from its nib.
appDelegate = (ProgAppDelegate *)[[UIApplication sharedApplication] delegate];
IDValue = 1;
textLabel.text=[self languageSelectedStringForKey:#"Welcome to Advance Localization"];
[super viewDidLoad];
}
What is causing this leak, and how can I fix it?
this is dealloc method:-
- (void)dealloc
{
[xmlParser release];
[parser release];
[nibLoadedCell release];
[super dealloc];
}
Do you ever call
[xmlParser release];
?
If not, you should release it when you no longer need it. Perhaps in the dealloc method of the same class in which that line appears.
You need to make NewsParser parser an instance variable and release it in the dealloc. Above, you init it, but you don't release it. Of course, you can't because it's a delegate of xmlParser. So, to make sure the object is retained, then properly released, it must be an ivar.
You never release FinalString (at least not in the code you posted)
this is held in the URL, which is held by the parser :)
Also, have you considered what would happen if this function is called twice?
Each time you say
xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
you would leak the previous xmlParser ;)
If you are allocating to an instance variable, you have to remember to release the previous object i.e.
[xmlParser release];
xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];

NSXmlParser and "modified after being freed" error

Just when I thought I had gotten the hang of Objective-C's memory-management this error strikes me from nowhere...
Please consider the following code:
#implementation JglpNewsEntryParser
- (JglpNewsEntryParser *) initialize : (NSString *)content {
self = [super init];
if (self) {
currentHeader = nil;
currentText = nil;
currentDate = nil;
currentFullArticleUrl = nil;
entries = [[NSMutableArray alloc] init];
NSData *data = [content dataUsingEncoding: [NSString defaultCStringEncoding]];
NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:data] autorelease];
[parser setDelegate: self];
[parser parse];
}
return self;
}
- (void)parser: (NSXMLParser *)parser didStartElement: (NSString *)elementName namespaceURI: (NSString *)namespaceURI qualifiedName: (NSString *)qName attributes: (NSDictionary *)attributeDict {
NSLog(#"Start!");
}
- (void)parser: (NSXMLParser *)parser didEndElement: (NSString *)elementName namespaceURI: (NSString *)namespaceURI qualifiedName: (NSString *)qName {
NSLog(#"End!");
}
- (void)parser: (NSXMLParser *)parser foundCharacters: (NSString *)content {
NSLog(#"Char!");
}
- (void)dealloc {
[super dealloc];
[entries release];
entries = nil;
}
The class is used in my unit test in the following manner:
- (void) testConstruct {
NSString *path = [[NSBundle bundleForClass:JglpNewsEntryParserTest.class] pathForResource: #"single-news-entry" ofType: #"html"];
NSError *error = nil;
NSString *data = [NSString stringWithContentsOfFile: path encoding: NSUTF8StringEncoding error: &error];
JglpNewsEntryParser *parser = [[[JglpNewsEntryParser alloc] initialize: data] autorelease];
STFail(#"");
}
After printing the "Start!", "End!" and "Char!" messages once, since the text XML contains only one entry, the test fails as it is supposed to at STFail. However, I do receive the following memory error message afterwards:
malloc: *** error for object 0xedf434: incorrect checksum for freed object - object was probably modified after being freed.
*** set a breakpoint in malloc_error_break to debug
Constructing the data object in initialize seems set off the doomsday machine. If I uncomment it, the message disappears.
// ...
/*NSData *data = [content dataUsingEncoding: [NSString defaultCStringEncoding]];
NSXMLParser *parser = [[[NSXMLParser alloc] initWithData:data] autorelease];
[parser setDelegate: self];
[parser parse];*/
}
return self;
}
Am I missing something when constructing the NSData object from the NSString?
Thanks for any suggestions and best regards
KC
Dealloc should do [super dealloc] after releasing all the instance variables:
- (void)dealloc {
[entries release];
entries = nil;
[super dealloc];
}
because it is dealloc in NSObject that actually frees the memory used by the object. When you set entries to nil, you are writing to a block of memory that has been freed already.
Some other comments:
It seems wrong to me that you are doing work in -init. I would recommend that you have a method (call it, say, -parse) that actually invokes the parser. At the moment you are performing quite complex ooperations on an object that isn't guranteed to be fully initialised.
Also, it's best not to call your init method -initialize: to avoid confusion with +initialize which has a specific meaning in Cocoa. I'd call it -initWithContent:
Also, your instance variables are initialised to nil before -init, so lines like
ivar = nil;
are pointless in init and you also need to release all your instance variables in dealloc.
The [super dealloc] should be called at the end. Plus release objects which you allocate. An allocated object can be released by sending a message nil to it like entries = nil.
ATB.

UITabelView reloaded from NSXMLParser (iphone SDK 4.0)

I am creating application that simply reads data from an XML file and displays it in a table view.
I created a "refresh" button when clicked i want it to redownload the xml file and display it again however it seems to crash my application if there is a XML file already downloaded.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
ipb = [[IPB alloc] init];
sectionTitle=[[NSMutableArray alloc]init];
currentURL=#"http://localhost:8888/xml/Sinnergy.xml";
[self reloadTableView];
[window makeKeyAndVisible];
return YES;
}
-(void)reloadTableView
{
pathURL = [NSURL URLWithString:currentURL];
parser = [[NSXMLParser alloc] initWithContentsOfURL:pathURL];
[parser setDelegate:self];
[parser parse];
[mainTableView reloadData];
}
You are leaking the parser, and if its an instance variable it might cause issues. You should go
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:pathURL];
[parser setDelegate:self];
[parser parse];
[parser release];
Also you are asking the parser to start parsing, but at that point of time you shouldn't be reloading the table, it should be in your
- (void)parserDidEndDocument:(NSXMLParser *)parser
delegate method. Try that and if it still crashes post the crash report

How can I disable a button while NSXMLParser runs, then enable it when it completes?

I have a viewController which imports XMLParser.h as the class xmlParser
I'm passing an NSURL object in my viewController to the xmlParser class with the getXML method below
goButton is the button I tap to call the getXML method below. I disable the button which I tapped to trigger the getXML method, but I'm not sure where to put the code to enable it again once the xmlParser has finished parsing the returned XML.
- (IBAction) getXML {
goButton.enabled = NO;
// allocate and initialize the xmlParser
xmlParser = [[XMLParser alloc] init];
// then generate the URL we are going to pass to it and call the fetchXML method passing the URL.
NSURL *xmlurl = [[NSURL alloc] initWithString:#"http://www.mysite.com/myfile.xml"];
[xmlParser fetchXMLFromURL:xmlurl];
// release objects
[xmlurl release];
[xmlParser release];
}
As per #Squeegy recommendation, I modified my code.
- (IBAction) getXML {
goButton.enabled = NO;
xmlParser = [[XMLParser alloc] init];
[self performSelectorInBackground:#selector(parseInBackground:) withObject:xmlParser];
}
- (void)parseInBackground:(XMLParser*)parser {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSURL *xmlurl = [[NSURL alloc] initWithString:#"http://www.mysite.com/myfile.xml"];
[parser fetchXMLFromURL:xmlurl];
[self performSelectorOnMainThread:#selector(didFinishXMLParsing:) withObject:parser];
[xmlurl release];
[pool drain];
}
- (void)didFinishXMLParsing:(NSXMLParser*)parser {
goButton.enabled = YES;
}
Looks to be working until it gets to the line
[self performSelectorOnMainThread:#selector(didFinishXMLParsing:) withObject:parser];
The compiler complains as follows:
2010-02-17 00:22:20.574 XMLApp[2443:521b] *** -[viewController performSelectorOnMainThread:withObject:]: unrecognized selector sent to instance 0x1285a0
2010-02-17 00:22:20.578 XMLApp[2443:521b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[viewController performSelectorOnMainThread:withObject:]: unrecognized selector sent to instance 0x1285a0'
2010-02-17 00:22:20.583 XMLApp[2443:521b] Stack: (
861696817,
860329709,
861700631,
861203093,
861166272,
18715,
846004025,
845672609,
848189713
)
- (IBAction)getXML {
goButton.enabled = NO;
xmlParser = [[XMLParser alloc] init];
NSURL *xmlurl = [[NSURL alloc] initWithString:#"http://www.mysite.com/myfile.xml"];
[xmlParser fetchXMLFromURL:xmlurl];
[self performSelectorInBackground:#selector(parseInBackground) withObject:xmlParser];
[xmlurl release];
[xmlParser release];
}
- (void)parseInBackground:(NSXMLParser*)parser {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[parser parse];
[self performSelectorOnMainThread:#selector(didFinishXMLParsing:)
withObject:parser
waitUntilDone:NO];
[pool drain];
}
- (void)didFinishXMLParsing:(NSXMLParser*)parser {
goButton.enabled = YES;
}
The trick is to do the processing on a background thread, which allows the UI to do stuff. When parsing is done, you have to make any UI changes back on the main thread.
When the parser finishes parsing, it will call it's delegate's:
- (void)parserDidEndDocument:(NSXMLParser *)parser
In that method, you can re-enable the button. You should probably do so with a performSelectorInMainThread call, since it involves changing a view.