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.
Related
Im having trouble understanding NSXMLParser. I have tried some external XML Parsers but i have had no luck. What i am trying to do is parse the GDATA Youtube API xml which retrieves the xml for videos. This is working fine i have the xml but its difficult reiterating through the elements. I just need an example that can retrieve the elements such as (media:thumbnail url="" )(/media:thumbnail)
How to i get the url value from the element media:thumbnail
The url i am requesting is https://gdata.youtube.com/feeds/api/videos?q=football+-soccer&orderby=published&start-index=11&max-results=10&v=2
This is how you can use NSXMLParser :
In your .h file declare :
NSMutableData *webPortFolio;
NSMutableString *soapResultsPortFolio;
NSURLConnection *conn;
//---xml parsing---
NSXMLParser *xmlParserPortFolio;
BOOL elementFoundPortFolio;
NSMutableURLRequest *req;
NSString *theXMLPortFolio;
NSString *strSoapMsg;
UIAlertView *alertView;
In your .m file use the following code:
-(void)callURL
{
//Your logic to call URL.
conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
if (conn)
{
webPortFolio = [[NSMutableData data] retain];
}
}
And to handle the response you can use following functions :
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[webPortFolio setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webPortFolio appendData:data];
}
-(void) connection:(NSURLConnection *) connection didFailWithError:(NSError *) error
{
NSLog(#"error...................%#",[error description]);
[webPortFolio release];
[connection release];
}
-(void) connectionDidFinishLoading:(NSURLConnection *) connection
{
//Check the request and returns the response.
NSLog(#"DONE. Received Bytes: %d", [webPortFolio length]);
theXMLPortFolio = [[NSString alloc]
initWithBytes: [webPortFolio mutableBytes]
length:[webPortFolio length]
encoding:NSUTF8StringEncoding];
//---shows the XML---
NSLog(#"shows the XML %#",theXMLPortFolio);
[theXMLPortFolio release];
if(xmlParserPortFolio)
{
[xmlParserPortFolio release];
}
xmlParserPortFolio = [[NSXMLParser alloc] initWithData: webPortFolio];
[xmlParserPortFolio setDelegate: self];
[xmlParserPortFolio setShouldResolveExternalEntities:YES];
[xmlParserPortFolio parse];
[webPortFolio release];
[connection release];
}
//---when the start of an element is found---
-(void) parser:(NSXMLParser *) parser
didStartElement:(NSString *) elementName
namespaceURI:(NSString *) namespaceURI
qualifiedName:(NSString *) qName
attributes:(NSDictionary *) attributeDict
{
if( [elementName isEqualToString:#"GetPortfolioListResult"])
{
if (!soapResultsPortFolio)
{
soapResultsPortFolio = [[NSMutableString alloc] init];
}
elementFoundPortFolio = TRUE;
NSLog(#"Registration...%#",soapResultsPortFolio);
}
else if([elementName isEqualToString:#"your_tag_name"])
{
elementFoundPortFolio = TRUE;
}
else if([elementName isEqualToString:#"your_tag_name"])
{
elementFoundPortFolio = TRUE;
}
else if([elementName isEqualToString:#"your_tag_name"])
{
elementFoundPortFolio = TRUE;
}
}
-(void)parser:(NSXMLParser *) parser foundCharacters:(NSString *)string
{
if (elementFoundPortFolio)
{
[soapResultsPortFolio appendString: string];
}
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
NSLog(#"Parser error %# ",[parseError description]);
}
//---when the end of element is found---
-(void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"GetPortfolioListResult"])
{
NSLog(#"display the soap results%#",soapResultsPortFolio);
}
else if([elementName isEqualToString:#"your_tag_name"])
{
//Perform required action
}
else if([elementName isEqualToString:#"your_tag_name"])
{
//Perform required action
}
else if([elementName isEqualToString:#"your_tag_name"])
{
//Perform required action
}
[soapResultsPortFolio setString:#""];
elementFoundPortFolio = FALSE;
}
EDIT :
if ([elementName isEqualToString:#"media:thumbnail"])
{
//Save your URL in an Array
}
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.
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]];
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.
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];
}
}
}