iPhone NSXMLParser (Error 9) - iphone

i try to parse within my iPhone SDK 4
http://de.news.search.yahoo.com/news/rss?p=iphone&ei=UTF-8&fl=0&x=wrt
there are some german umlaute
<description><![CDATA[Mehr als die Hälfte der Belegschaft des weltweit größten]]></description>
As I read in another forum as long they are wrapped in CDATA it should be fine.
But in the moment the parser found the element "description"
he breaks with:
error parsing XML: Unable to download story feed from web site (Error code 9 ) http://de.news.search.yahoo.com/news/rss?p=iphone&ei=UTF-8&fl=0&x=wrt
The english feeds works fine !? So its something with this umlaute, but what can i do?
greets
chris
JUST FOR UNDERSTANDING .. HERE MY WHOLE PARSER
- (void)parseXMLFileAtURL:(NSString *)URL {
aktuelleUrl = URL;
stories = [[NSMutableArray alloc] init];
NSURL *xmlURL = [NSURL URLWithString:aktuelleUrl];
// here, for some reason you have to use NSClassFromString when trying to alloc NSXMLParser, otherwise you will get an object not found error
// this may be necessary only for the toolchain
rssParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
[rssParser setDelegate:self];
// Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
[rssParser setShouldProcessNamespaces:NO];
[rssParser setShouldReportNamespacePrefixes:NO];
[rssParser setShouldResolveExternalEntities:NO];
[rssParser parse];
}
- (void)parserDidStartDocument:(NSXMLParser *)parser{
//NSLog(#"found file and started parsing");
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
NSString * errorString = [NSString stringWithFormat:#"Unable to download story feed from web site (Error code %i ) %#", [parseError code], aktuelleUrl];
NSLog(#"error parsing XML: %#", errorString);
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
NSLog(#"found this element: %#", elementName);
currentElement = [elementName copy];
if ([elementName isEqualToString:#"channel"]) {
channel1item2 = 1;
// clear out our story item caches...
// item = [[NSMutableDictionary alloc] init];
currentTitle = [[NSMutableString alloc] init];
// currentDate = [[NSMutableString alloc] init];
currentSummary = [[NSMutableString alloc] init];
currentLink = [[NSMutableString alloc] init];
}
if ([elementName isEqualToString:#"item"]) {
channel1item2 = 2;
// clear out our story item caches...
item = [[NSMutableDictionary alloc] init];
currentTitle = [[NSMutableString alloc] init];
currentDate = [[NSMutableString alloc] init];
currentSummary = [[NSMutableString alloc] init];
currentLink = [[NSMutableString alloc] init];
currentEncoded = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
//NSLog(#"ended element: %# c1i2: %i", elementName, channel1item2);
if (channel1item2 == 1) {
if (![currentTitle isEqualToString:#""]) { aCurrentTitle = currentTitle; }
if (![currentLink isEqualToString:#""]) { aCurrentLink = currentLink; }
if (![currentSummary isEqualToString:#""]) {aCurrentSummary = currentSummary; }
}
else if ([elementName isEqualToString:#"item"]) {
[item setObject:currentTitle forKey:#"title"];
[item setObject:currentLink forKey:#"link"];
[item setObject:currentSummary forKey:#"summary"];
[item setObject:currentDate forKey:#"date"];
[item setObject:currentEncoded forKey:#"content:encoded"];
[stories addObject:[item copy]];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
//NSLog(#"found characters: %#", string);
// save the characters for the current item...
if ([currentElement isEqualToString:#"title"]) {
[currentTitle appendString:string];
} else if ([currentElement isEqualToString:#"link"]) {
[currentLink appendString:string];
//NSLog(#"parselink '%#'",string);
} else if ([currentElement isEqualToString:#"description"]) {
[currentSummary appendString:string];
} else if ([currentElement isEqualToString:#"pubDate"]) {
[currentDate appendString:string];
} else if ([currentElement isEqualToString:#"content:encoded"]) {
[currentEncoded appendString:string];
}
else if ([currentElement isEqualToString:#"media:content"]) {
//NSLog(#"mediacontent %#",string);
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
// NSLog(#"all done!");
//NSLog(#"stories array has %d items", [stories count]);
}

Perhaps look into -stringWithContentsOfURL:usedEncoding:error: to download the XML:
NSError *error = nil;
NSStringEncoding encoding;
NSString *xmlFeedStr = [NSString stringWithContentsOfURL:[NSURL URLWithString:#"http://de.news.search.yahoo.com/news/rss?p=iphone&ei=UTF-8&fl=0&x=wrt"] usedEncoding:&encoding error:&error];
NSXMLParser *rssParser = [[NSXMLParser alloc] initWithData:[xmlFeedStr dataUsingEncoding:encoding allowLossyConversion:YES]];
...
[rssParser release];

From the documentation:
NSXMLParserInvalidCharacterError = 9
Perhaps the document is not really encoded in UTF-8?

Now I solved it different. Wrote my own XML parser just simple for my needs and with the following routine, i found in some forum, i encode the xml string. Also I marked the answer above as 'accepted' as it lead me into the right direction.
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)s {
[resultString appendString:s];
}
- (NSString*)convertEntiesInString:(NSString*)s {
resultString = [[NSMutableString alloc] init];
if(s == nil) {
//NSLog(#"ERROR : Parameter string is nil");
}
NSString* xmlStr = [NSString stringWithFormat:#"<d>%#</d>", s];
NSData *data = [xmlStr dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
NSXMLParser* xmlParse = [[NSXMLParser alloc] initWithData:data];
[xmlParse setDelegate:self];
[xmlParse parse];
NSString* returnStr = [[NSString alloc] initWithFormat:#"%#",resultString];
return returnStr;
}
objectsResultStr = [self convertEntiesInString:orgString]];

Related

Error code 5 in application

I have developed one application to fetch RSS feed. I am getting this error code 5 for some URLs where as som others are working fine.
I know this error means the xml is invalid. But for my app, I have not written any xml files by my own.
Please tell me the probable reasons for this and let me know the solution
import "RootViewController.h"
#implementation RootViewController
(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
if ([stories count] == 0) {
path = #"http://172.19.58.108:8080/jwplayer/JSP/Videolist.jsp";
[self parseXMLFileAtURL:path];
}
}
-(void)parseXMLFileAtURL:(NSString *)URL{
stories = [[NSMutableArray alloc]init];
NSURL *xmlURL = [NSURL URLWithString:URL];
rssParser = [[NSXMLParser alloc]initWithContentsOfURL:xmlURL];
[rssParser setDelegate:self];
[rssParser setShouldProcessNamespaces:NO];
[rssParser setShouldReportNamespacePrefixes:NO];
[rssParser setShouldResolveExternalEntities:NO];
[rssParser parse];
}
-(void)parserDidStartDocument:(NSXMLParser *)parser{
NSLog(#"Found file and started parsing");
}
-(void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{
NSString *errorString = [NSString stringWithFormat:#"Unable to download story feed from website (Error Code %i)", [parseError code]];
NSLog(#"Error parsing xml: %#", errorString);
UIAlertView *errorAlert = [[UIAlertView alloc]initWithTitle:#"Error loading content" message:errorString delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
currentElement = [elementName copy];
if ([elementName isEqualToString:#"item"]) {
item = [[NSMutableDictionary alloc]init];
currentTitle = [[NSMutableString alloc]init];
currentDate = [[NSMutableString alloc]init];
currentSummary = [[NSMutableString alloc]init];
currentLink = [[NSMutableString alloc]init];
}
}
-(void)parser: (NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"item"]) {
[item setObject:currentTitle forKey:#"title"];
[item setObject:currentDate forKey:#"date"];
[item setObject:currentSummary forKey:#"summary"];
[item setObject:currentLink forKey:#"link"];
[stories addObject:[item copy]];
NSLog(#"adding story: %#", currentTitle);
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([currentElement isEqualToString:#"title"]) {
[currentTitle appendString:string];
}
else if ([currentElement isEqualToString:#"link"]) {
[currentLink appendString:string];
}
else if ([currentElement isEqualToString:#"description"]) {
[currentSummary appendString:string];
}
else if ([currentElement isEqualToString:#"pubDate"]) {
[currentDate appendString:string];
}
}
-(void)parserDidEndDocument:(NSXMLParser *)parser{
[activityIndicator stopAnimating];
[activityIndicator removeFromSuperview];
NSLog(#"all done");
NSLog(#"stories array has %d items", [stories count]);
[newsTable reloadData];
}
Please check your library class for Rss feed parsing. Use standard library class, change the the code accordingly.

NSXMLParserErrorDomain error 31

I getting this error when retrieve xml request from http://www.cbr.ru/scripts/XML_daily.asp
XML code like this:
<?xml version="1.0" encoding="windows-1251" ?>
<ValCurs Date="01.03.2011" name="Foreign Currency Market">
<Valute ID="R01010">
<NumCode>036</NumCode>
<CharCode>AUD</CharCode>
<Nominal>1</Nominal>
<Name>Австралийский доллар</Name>
<Value>29,3508</Value>
</Valute>
<Valute ID="R01020A">
<NumCode>944</NumCode>
<CharCode>AZN</CharCode>
<Nominal>1</Nominal>
<Name>Азербайджанский манат</Name>
<Value>36,3374</Value>
</Valute>
My code is:
-(void)parserDidStartDocument:(NSXMLParser *)parser
{
[articles removeAllObjects];
}
-(void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict
{
currentElement = elementName;
if ([elementName isEqualToString:#"ValCurs"]) {
itemActive = YES;
currentValute = [[NSMutableString alloc]init];
currentNumCode = [[NSMutableString alloc]init];
currentCharCode = [[NSMutableString alloc]init];
nominal = [[NSMutableString alloc]init];
currentName = [[NSMutableString alloc]init];
currentValue = [[NSMutableString alloc]init];
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (itemActive) {
NSString *fixedString = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([currentElement isEqualToString:#"Valute"])
[currentValute appendString:fixedString];
if ([currentElement isEqualToString:#"NumCode"])
[currentNumCode appendString:fixedString];
if ([currentElement isEqualToString:#"CharCode"])
[currentCharCode appendString:fixedString];
if ([currentElement isEqualToString:#"Nominal"])
[nominal appendString:fixedString];
if ([currentElement isEqualToString:#"Name"])
[currentName appendString:fixedString];
if ([currentElement isEqualToString:#"Value"])
[currentValue appendString:fixedString];
}
}
-(void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"ValCurs"]) {
NSDictionary *record = [NSDictionary dictionaryWithObjectsAndKeys:
currentValute,#"Valute",
currentNumCode,#"NumCode",
currentCharCode,#"CharCode",
nominal,#"nominal",
currentName,#"Name",
currentValue,#"Value",
nil];
[articles addObject:record];
[currentNumCode release];
[currentCharCode release];
[currentValute release];
[nominal release];
[currentName release];
[currentValue release];
itemActive = NO;
}
}
-(void)parserDidEndDocument:(NSXMLParser *)parser
{
NSLog(#"%#",articles);
//text.text = (#"%#",currentCharCode);
}
-(void)retrieveXML:(id)sender
{
[parser parse];
}
........
- (void)viewDidLoad {
[super viewDidLoad];
articles = [[NSMutableArray alloc]init];
NSString *myURL = [NSString stringWithFormat:#"http://www.cbr.ru/scripts/XML_daily.asp"];
NSURL *url = [NSURL URLWithString:myURL];
//NSString *urla = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
parser = [[NSXMLParser alloc]initWithContentsOfURL:url];
parser.delegate = self;
[self createUI];
}
From NSXMLParser reference -NSXMLParserUnknownEncodingError = 31.
May be i need use encoding to NSWindowsCP1251StringEncoding for solve problem ?
NSXMLParserUnknownEncodingError = 31 occurs when document encoding is unknown.
Try this:
NSString *myStr = [[NSString alloc] initWithData:myData encoding:NSWindowsCP1251StringEncoding];
myStr = [myStr stringByReplacingOccurrencesOfString:#"encoding=\"windows-1251\"" withString:#""];
NSData* aData = [myStr dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:aData];

RSS Reader error

I am currently doing an application which make use of the RSS Feed from http://www.learnerstogether.net/. However i keep getting the error unable to download the XML data from the website. Can someone tell me what is wrong.
#implementation Parser
#synthesize items, responseData;
#synthesize currentTitle;
#synthesize currentDate;
#synthesize currentSummary;
#synthesize currentLink;
#synthesize currentPodcastLink;
- (void)parseRssFeed:(NSString *)url withDelegate:(id)aDelegate {
[self setDelegate:aDelegate];
responseData = [[NSMutableData data] retain];
NSURL *baseURL = [[NSURL URLWithString:url] retain];
NSURLRequest *request = [NSURLRequest requestWithURL:baseURL];
[[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSString * errorString = [NSString stringWithFormat:#"Unable to download xml data (Error code %i )", [error code]];
UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle:#"Error loading content" message:errorString delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
self.items = [[NSMutableArray alloc] init];
NSXMLParser *rssParser = [[NSXMLParser alloc] initWithData:responseData];
[rssParser setDelegate:self];
[rssParser parse];
}
#pragma mark rssParser methods
- (void)parserDidStartDocument:(NSXMLParser *)parser {
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
currentElement = [elementName copy];
if ([elementName isEqualToString:#"item"]) {
item = [[NSMutableDictionary alloc] init];
self.currentTitle = [[NSMutableString alloc] init];
self.currentDate = [[NSMutableString alloc] init];
self.currentSummary = [[NSMutableString alloc] init];
self.currentLink = [[NSMutableString alloc] init];
self.currentPodcastLink = [[NSMutableString alloc] init];
}
// podcast url is an attribute of the element enclosure
if ([currentElement isEqualToString:#"enclosure"]) {
[currentPodcastLink appendString:[attributeDict objectForKey:#"url"]];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"item"]) {
[item setObject:self.currentTitle forKey:#"title"];
[item setObject:self.currentLink forKey:#"link"];
[item setObject:self.currentSummary forKey:#"summary"];
[item setObject:self.currentPodcastLink forKey:#"podcastLink"];
// Parse date here
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:#"E, d LLL yyyy HH:mm:ss Z"]; // Thu, 18 Jun 2010 04:48:09 -0700
NSDate *date = [dateFormatter dateFromString:self.currentDate];
[item setObject:date forKey:#"date"];
[items addObject:[item copy]];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([currentElement isEqualToString:#"title"]) {
[self.currentTitle appendString:string];
} else if ([currentElement isEqualToString:#"link"]) {
[self.currentLink appendString:string];
} else if ([currentElement isEqualToString:#"description"]) {
[self.currentSummary appendString:string];
} else if ([currentElement isEqualToString:#"pubDate"]) {
[self.currentDate appendString:string];
NSCharacterSet* charsToTrim = [NSCharacterSet characterSetWithCharactersInString:#" \n"];
[self.currentDate setString: [self.currentDate stringByTrimmingCharactersInSet: charsToTrim]];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
if ([_delegate respondsToSelector:#selector(receivedItems:)])
[_delegate receivedItems:items];
else
{
[NSException raise:NSInternalInconsistencyException
format:#"Delegate doesn't respond to receivedItems:"];
}
}
#pragma mark Delegate methods
- (id)delegate {
return _delegate;
}
- (void)setDelegate:(id)new_delegate {
_delegate = new_delegate;
}
- (void)dealloc {
[items release];
[responseData release];
[super dealloc];
}
#end
Your error has absolutely nothing to do with the RSS parsing aspect of this. What's more, you haven't even pasted in the full error. You should log the error object itself in your implementation of -connection:didFailWithError:. That should give you a human-readable description of what went wrong.

Can't manage to find any answers to the last bug my app has ... [challenge inside ;)]

I finally get no leaks in my app but I still manage to get my app to crash from time to time ... it is really rare but it pisses me off ;)
Here is what I get :
2010-05-11 19:36:29.487 Infonul[2457:20b] *** -[NSCFString _setParserError:]: unrecognized selector sent to instance 0x3cddb80
[Session started at 2010-05-11 19:36:29 +0200.]
2010-05-11 19:36:29.487 Infonul[2457:20b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFString _setParserError:]: unrecognized selector sent to instance 0x3cddb80'
2010-05-11 19:36:29.488 Infonul[2457:20b] Stack: (
9479259,
2423766587,
9861179,
9430646,
9283266,
4372334,
56536,
4191652,
4191507,
12699064,
12697112,
12697826,
12697826,
12700310,
12359637,
9263329,
9260104,
825261,
825458,
23633923
)
Here is where it seems to fail :
// after having downloaded the file to parse
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
CommentsParserDelegate *commentsParserDelegate = [[CommentsParserDelegate alloc] initWithController:self];
//commentsParserDelegate.commentController = self;
commentsParser = [[NSXMLParser alloc] initWithData:self.activeDownload];
[commentsParser setDelegate:commentsParserDelegate];
[commentsParser parse]; //last function called before crash
}
No idea why app crashes and I don't understand what the debugger is trying to tell me :D
Hopefully, someone gets some idea ;)
Thank you.
Gotye.
The debugger is trying to tell you that you (or, more likely, the framework) are trying to invoke a method called _setParserError on an object of class NSString. There's no such method in NSString.
Here is the code of "CommentsParserDelegate.m"
//
// CommentsParserDelegate.m
// Infonul
//
// Created by eef16514f684e5d on 26/03/10.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import "CommentsParserDelegate.h"
#implementation CommentsParserDelegate
#synthesize currentElement;
//#synthesize commentController;
- (id)initWithController:(CommentsViewController *)comment {
if (self = [super init]) {
commentController = comment;
months = [[NSArray alloc] initWithObjects:#"Jan.",#"Fév.",#"Mars",#"Avril",#"Mai",#"Juin",#"Juil.",#"Août",#"Sept.",#"Oct.",#"Nov.",#"Déc.",nil];
}
return self;
}
- (void)parserDidStartDocument:(NSXMLParser *)parser {
comments = [[NSMutableArray alloc] init];
//currentElement = [[NSString alloc] init];
currentContent = [[NSMutableString alloc] init];
currentAuthor = [[NSMutableString alloc] init];
currentDate = [[NSMutableString alloc] init];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
self.currentElement = elementName;
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"item"]) {
// save values to an item, then store that item into the array...
CommentRecord *comment = [[CommentRecord alloc] init];
[comment setAuthor:[[[NSString alloc] initWithString:[currentAuthor stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]] autorelease]];
[currentAuthor setString:#""];
[comment setContent:[[[NSString alloc] initWithString:[currentContent stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]] autorelease]];
[currentContent setString:#""];
NSString *tempDate = [[[NSString alloc] initWithString:[currentDate stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]] autorelease];
NSMutableString *tempString = [[NSMutableString alloc] initWithString:[tempDate substringToIndex:2]];
NSString *month = [[tempDate substringFromIndex:3] substringToIndex:2];
[tempString appendString:#" "];
[tempString appendString:[months objectAtIndex:[month intValue]-1]];
[tempString appendString:#" "];
[tempString appendString:[[tempDate substringFromIndex:6] substringToIndex:4]];
[tempString appendString:#" à "];
[tempString appendString:[[tempDate substringFromIndex:11] substringToIndex:8]];
[comment setDate:[[[NSString alloc] initWithString:tempString] autorelease]];
[tempString release];
[currentDate setString:#""];
[comments addObject:comment];
[comment release];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if (([currentElement isEqualToString:#"author"])) {
[currentAuthor appendString:[self flattenTEXT:string]];
}
else if (([currentElement isEqualToString:#"content"])) {
[currentContent appendString:string];
}
else if (([currentElement isEqualToString:#"date"])) {
[currentDate appendString:string];
}
}
- (NSString *)flattenTEXT:(NSString *)link
{
//link = [link stringByReplacingOccurrencesOfString:#" " withString:#""];
link = [link stringByReplacingOccurrencesOfString:#"\n" withString:#""];
link = [link stringByReplacingOccurrencesOfString:#"\t" withString:#""];
link = [link stringByReplacingOccurrencesOfString:#"\r" withString:#""];
return link;
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
[currentDate release];
[currentContent release];
[currentAuthor release];
[self.currentElement release];
[commentController displayData:comments];
}
- (void)dealloc {
[comments release];
[months release];
[super dealloc];
}
/*
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
NSLog(parseError.description);
}
*/
#end
Would that help ?
Is the log always saying that the selector is being sent to an NSString object, or does the object type vary? If it varies, it's usually a sign of a memory management problem.

Iphone NSXMLParser NSCFString memory leak

I am building an app that parses an rss feed. In the app there are two different types of feeds with different names for the elements in the feed, so I have created an NSXMLParser NSObject that takes the name of the elements of each feed before parsing. Here is my code:
NewsFeedParser.h
#import
#interface NewsFeedParser : NSObject {
NSInteger NewsSelectedCategory;
NSXMLParser *NSXMLNewsParser;
NSMutableArray *newsCategories;
NSMutableDictionary *NewsItem;
NSMutableString *NewsCurrentElement, *NewsCurrentElement1, *NewsCurrentElement2, *NewsCurrentElement3;
NSString *NewsItemType, *NewsElement1, *NewsElement2, *NewsElement3;
NSInteger NewsNumElements;
}
- (void) parseXMLFileAtURL:(NSString *)URL;
#property(nonatomic, retain) NSString *NewsItemType;
#property(nonatomic, retain) NSString *NewsElement1;
#property(nonatomic, retain) NSString *NewsElement2;
#property(nonatomic, retain) NSString *NewsElement3;
#property(nonatomic, retain) NSMutableArray *newsCategories;
#property(assign, nonatomic) NSInteger NewsNumElements;
#end
NewsFeedParser.m
#import "NewsFeedParser.h"
#implementation NewsFeedParser
#synthesize NewsItemType;
#synthesize NewsElement1;
#synthesize NewsElement2;
#synthesize NewsElement3;
#synthesize newsCategories;
#synthesize NewsNumElements;
- (void)parserDidStartDocument:(NSXMLParser *)parser{
}
- (void)parseXMLFileAtURL:(NSString *)URL
{
newsCategories = [[NSMutableArray alloc] init];
URL = [URL stringByReplacingOccurrencesOfString:#" " withString:#""];
URL = [URL stringByReplacingOccurrencesOfString:#"\n" withString:#""];
URL = [URL stringByReplacingOccurrencesOfString:#" " withString:#""];
//you must then convert the path to a proper NSURL or it won't work
NSURL *xmlURL = [NSURL URLWithString:URL];
// here, for some reason you have to use NSClassFromString when trying to alloc NSXMLParser, otherwise you will get an object not found error
// this may be necessary only for the toolchain
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
NSXMLNewsParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
[NSXMLNewsParser setDelegate:self];
// Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
[NSXMLNewsParser setShouldProcessNamespaces:NO];
[NSXMLNewsParser setShouldReportNamespacePrefixes:NO];
[NSXMLNewsParser setShouldResolveExternalEntities:NO];
[NSXMLNewsParser parse];
[NSXMLNewsParser release];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
NSString * errorString = [NSString stringWithFormat:#"Unable to download story feed from web site (Error code %i )", [parseError code]];
NSLog(#"error parsing XML: %#", errorString);
UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle:#"Error loading content" message:errorString delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
[errorAlert release];
[errorString release];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
NewsCurrentElement = [elementName copy];
if ([elementName isEqualToString:NewsItemType])
{
// clear out our story item caches...
NewsItem = [[NSMutableDictionary alloc] init];
NewsCurrentElement1 = [[NSMutableString alloc] init];
NewsCurrentElement2 = [[NSMutableString alloc] init];
if(NewsNumElements == 3)
{
NewsCurrentElement3 = [[NSMutableString alloc] init];
}
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:NewsItemType])
{
// save values to an item, then store that item into the array...
[NewsItem setObject:NewsCurrentElement1 forKey:NewsElement1];
[NewsItem setObject:NewsCurrentElement2 forKey:NewsElement2];
if(NewsNumElements == 3)
{
[NewsItem setObject:NewsCurrentElement3 forKey:NewsElement3];
}
[newsCategories addObject:[[NewsItem copy] autorelease]];
[NewsCurrentElement release];
[NewsCurrentElement1 release];
[NewsCurrentElement2 release];
if(NewsNumElements == 3)
{
[NewsCurrentElement3 release];
}
[NewsItem release];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
//NSLog(#"found characters: %#", string);
// save the characters for the current item...
if ([NewsCurrentElement isEqualToString:NewsElement1]) {
[NewsCurrentElement1 appendString:string];
} else if ([NewsCurrentElement isEqualToString:NewsElement2]) {
[NewsCurrentElement2 appendString:string];
} else if (NewsNumElements == 3 && [NewsCurrentElement isEqualToString:NewsElement3])
{
[NewsCurrentElement3 appendString:string];
}
}
- (void)dealloc {
[super dealloc];
[newsCategories release];
[NewsItemType release];
[NewsElement1 release];
[NewsElement2 release];
[NewsElement3 release];
}
When I create an instance of the class I do like so:
NewsFeedParser *categoriesParser = [[NewsFeedParser alloc] init];
if(newsCat == 0)
{
categoriesParser.NewsItemType = #"article";
categoriesParser.NewsElement1 = #"category";
categoriesParser.NewsElement2 = #"catid";
}
else
{
categoriesParser.NewsItemType = #"article";
categoriesParser.NewsElement1 = #"category";
categoriesParser.NewsElement2 = #"feedUrl";
}
[categoriesParser parseXMLFileAtURL:feedUrl];
newsCategories = [[NSMutableArray alloc] initWithArray:categoriesParser.newsCategories copyItems:YES];
[self.tableView reloadData];
[categoriesParser release];
If I run the app with the leaks instrument, the leaks point to the [NSXMLNewsParser parse] call in the NewsFeedParser.m.
Here is a screen shot of the Leaks instrument with the NSCFStrings leaking:
http://img139.imageshack.us/img139/3997/leaks.png
For the life of me I can't figure out where these leaks are coming from. Any help would be greatly appreciated.
The leak occurred in the didStartElement method. I was copying elementName without releasing it.
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
NewsCurrentElement = [[elementName copy] autorelease];
if ([elementName isEqualToString:NewsItemType])
{
// clear out our story item caches...
NewsItem = [[NSMutableDictionary alloc] init];
NewsCurrentElement1 = [[NSMutableString alloc] init];
NewsCurrentElement2 = [[NSMutableString alloc] init];
if(NewsNumElements == 3)
{
NewsCurrentElement3 = [[NSMutableString alloc] init];
}
}
}
You might also want to release (if necessary) the allocated NSMutableString properties before allocating another NSMutableString into the property like so:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if (NewsCurrentElement) {
[NewsCurrentElement release], NewsCurrentElement = nil;
}
NewsCurrentElement = [[elementName copy] autorelease];
if ([elementName isEqualToString:NewsItemType]) {
// clear out our story item caches...
if (NewsItem) {
[NewsItem release], NewsItem = nil;
}
NewsItem = [[NSMutableDictionary alloc] init];
if (NewsCurrentElement1) {
[NewsCurrentElement1 release], NewsCurrentElement1 = nil;
}
NewsCurrentElement1 = [[NSMutableString alloc] init];
if (NewsCurrentElement2) {
[NewsCurrentElement2 release], NewsCurrentElement2 = nil;
}
NewsCurrentElement2 = [[NSMutableString alloc] init];
if(NewsNumElements == 3) {
if (NewsCurrentElement3) {
[NewsCurrentElement3 release], NewsCurrentElement3 = nil;
}
NewsCurrentElement3 = [[NSMutableString alloc] init];
}
}
}