I am trying to parse Data from multiple RSS feeds. If I use a single feed I am able to display the information in a table without any issues. I am using the title elements and loading them in a table for display.
When I try and load multiple RSS feeds I am able to append the feeds in a NSMutableData object but when I parse the data I only see the first feeds in the table.
In the view did load method I use fast enumeration to cycle through the different feeds.
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"News";
self.navigationItem.leftBarButtonItem = self.editButtonItem;
// Create an array that holds the URLs of the RSS feeds
NSMutableArray *RSSTempArray = [[NSMutableArray alloc] initWithObjects:kFLOCyclingURL, kTriathleteURL, kSlowtwitchURL, kCyclingNewsURL, nil];
//NSMutableArray *RSSTempArray = [[NSMutableArray alloc] initWithObjects:kFLOCyclingURL, nil];
//NSMutableArray *RSSTempArray = [[NSMutableArray alloc] initWithObjects:kTriathleteURL, nil];
//NSMutableArray *RSSTempArray = [[NSMutableArray alloc] initWithObjects:kSlowtwitchURL, nil];
//NSMutableArray *RSSTempArray = [[NSMutableArray alloc] initWithObjects:kCyclingNewsURL, nil];
self.RSSFeedArray = RSSTempArray;
NSMutableData *tempData = [[NSMutableData alloc] init];
self.RSSFeedData = tempData;
[self.RSSFeedData setLength: 0];
for (NSString *element in self.RSSFeedArray)
{
NSLog(@"The current element is %@", element);
// Loading the data from the RSS feed. This creates the connection for the NSURLConnectionDelegate Methods.
NSURLRequest *req = [[NSURLRequest alloc] initWithURL: [NSURL URLWithString: element]];
NSURLConnection *con = [[NSURLConnection alloc] initWithRequest: req delegate: self];
// This gives you access the the activity indicator in the top bar.
UIApplication.sharedApplication.networkActivityIndicatorVisible = YES;
// Tests to make sure the connection exists and sets up the NSMutableData object if it does exist.
if (con)
{
NSLog(@"Connected");
NSMutableData *data = [[NSMutableData alloc] init];
self.receivedData = data;
}
else
{
UIAlertView * alert = [[UIAlertView alloc] initWithTitle: @"Error" message:@"Error connecting to server" delegate:self cancelButtonTitle:@"Nuts" otherButtonTitles:nil];
[alert show];
}
}
NSLog (@"Out of the RSS Loop");
}
In the NSURLConnection methods I append the feed data as it comes in and then once it is complete I append it to the RSSFeedData object. You can see the accumulation in the console print out below. I have a test loop in the connectionDidFinishLoading method to ensure the parser is not called before all feeds have been downloaded. Once they have I create a new thread and parse the data.
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// This gives you access the the activity indicator in the top bar. It is a UIApplication item. Pretty cool.
UIApplication.sharedApplication.networkActivityIndicatorVisible = YES;
// Test to make sure the data array is created.
if (!receivedData)
{
NSMutableData *data = [[NSMutableData alloc] init];
self.receivedData = data;
}
// This sets up the connection and sets the received data object to 0
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
NSLog(@"remote url returned %d %@",[httpResponse statusCode],[NSHTTPURLResponse localizedStringForStatusCode:[httpResponse statusCode]]);
[receivedData setLength: 0];
//currentlyReadingFeeds = YES;
//NSLog(@"currentlyReadingFeeds turned on");
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-(void) connection:(NSURLConnection *)connection didReceiveData: (NSData *) data
{
// This appends the data to the receivedData object as chunks are received
NSLog(@"Data Received");
[receivedData appendData: data];
if (self.receivedData == nil)
{
NSLog(@"No Data Received");
}
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-(void) connection:(NSURLConnection *)connection didFailWithError: (NSError *) error
{
// This give you access the the activity indicator in the top bar. It is a UIApplication item. Pretty cool.
UIApplication.sharedApplication.networkActivityIndicatorVisible = NO;
NSLog(@"Failed With Error");
self.receivedData = nil;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:[NSString stringWithFormat:@"Connection failed! Error - %@ (URL: %@)", [error localizedDescription],[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]] delegate:self cancelButtonTitle:@"Bummer" otherButtonTitles:nil];
[alert show];
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-(void) connectionDidFinishLoading:(NSURLConnection *)connection
{
static NSInteger i = 0;
i++;
NSLog(@"i = %i", i);
NSLog(@"RSSFeedArray = %i", [self.RSSFeedArray count]);
// Checks to see if the receivedData array is nil
if (self.receivedData == nil)
{
NSLog(@"NSData File nil");
}
// This is a test to see if any data has been received
NSLog(@"I've downloaded: %d bytes", [receivedData length]);
currentlyReadingFeeds = NO;
NSLog(@"currentlyReadingFeeds turned off");
[self.RSSFeedData appendData: self.receivedData];
NSLog(@"The RSSFeedData Object currently contains %d bytes", [RSSFeedData length]);
//I am moving the XMLParser methods outside of the URL Connection methods since I am connecting to multiple sites. Each time I connect to a new site I clear my array.
if (i == [self.RSSFeedArray count])
{
NSLog(@"I am parsing");
NSLog(@"Inside the Parsing call the RSSFeedData Object contains %d bytes", [RSSFeedData length]);
// This sets up the array used in the NSXMLParser methods for gathering the parsed elements. Cuurently it adds all the <title> elements
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
self.testingArray = tempArray;
// This sets up the string used in the NSXMLParser methods for gathering string characters as they are collected by the parser.
NSMutableString *tempString = [[NSMutableString alloc] init];
self.currentParsedCharacterData = tempString;
// Start up the Parser in a seperate queue on Grand Central Dispatch. I have to use self on the parseRSSData method I created.
myQueue = dispatch_queue_create("com.flocycling.gcdparser", NULL);
dispatch_async(myQueue, ^ { [self parseRSSData: RSSFeedData];
[self.myTableView reloadData]; } );
}
}
Once I have the data I call the parser methods.
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString: kTitleElement])
{
currentlyAccumulatingParsedCharacters = YES;
[currentParsedCharacterData setString: @""];
}
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString: kTitleElement])
{
currentlyAccumulatingParsedCharacters = NO;
NSLog(@"Title: %@", currentParsedCharacterData);
// This adds the finished string to the array for the table. You need to create an object here or it ends up copying everything to the same
// address and all the elements are the same
NSString *tempString = [NSString stringWithFormat: currentParsedCharacterData];
[testingArray addObject: tempString];
}
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// The parser delivers parsed character data (PCDATA) in chunks, not necessarily all at once.
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (currentlyAccumulatingParsedCharacters)
{
[self.currentParsedCharacterData appendString: string];
}
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
}
You can see in the console print out that the data is being accumulated for each feed. I have tested each feed individually and the bytes all add up to what is being shown in the print out. Does anyone have any idea why I am not seeing all the data in the table?
2012-06-28 15:37:02.356 FLO Cycling[21958:15e03] The current element is http://flocycling.blogspot.com/feeds/posts/default?alt=rss
2012-06-28 15:37:02.361 FLO Cycling[21958:15e03] Connected
2012-06-28 15:37:02.364 FLO Cycling[21958:15e03] The current element is http://triathlon.competitor.com/feed
2012-06-28 15:37:02.365 FLO Cycling[21958:15e03] Connected
2012-06-28 15:37:02.367 FLO Cycling[21958:15e03] The current element is http://www.slowtwitch.com/rss
2012-06-28 15:37:02.368 FLO Cycling[21958:15e03] Connected
2012-06-28 15:37:02.368 FLO Cycling[21958:15e03] The current element is http://feeds.feedburner.com/cyclingnews/news?format=xml
2012-06-28 15:37:02.369 FLO Cycling[21958:15e03] Connected
2012-06-28 15:37:02.369 FLO Cycling[21958:15e03] Out of the RSS Loop
2012-06-28 15:37:02.404 FLO Cycling[21958:15e03] remote url returned 200 no error
2012-06-28 15:37:02.407 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:02.409 FLO Cycling[21958:15e03] i = 1
2012-06-28 15:37:02.410 FLO Cycling[21958:15e03] RSSFeedArray = 4
2012-06-28 15:37:02.411 FLO Cycling[21958:15e03] I've downloaded: 6934 bytes
2012-06-28 15:37:02.412 FLO Cycling[21958:15e03] currentlyReadingFeeds turned off
2012-06-28 15:37:02.412 FLO Cycling[21958:15e03] The RSSFeedData Object currently contains 6934 bytes
2012-06-28 15:37:02.505 FLO Cycling[21958:15e03] remote url returned 200 no error
2012-06-28 15:37:02.507 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:02.508 FLO Cycling[21958:15e03] i = 2
2012-06-28 15:37:02.509 FLO Cycling[21958:15e03] RSSFeedArray = 4
2012-06-28 15:37:02.511 FLO Cycling[21958:15e03] I've downloaded: 30916 bytes
2012-06-28 15:37:02.512 FLO Cycling[21958:15e03] currentlyReadingFeeds turned off
2012-06-28 15:37:02.513 FLO Cycling[21958:15e03] The RSSFeedData Object currently contains 37850 bytes
2012-06-28 15:37:02.514 FLO Cycling[21958:15e03] remote url returned 200 no error
2012-06-28 15:37:02.515 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:02.516 FLO Cycling[21958:15e03] i = 3
2012-06-28 15:37:02.517 FLO Cycling[21958:15e03] RSSFeedArray = 4
2012-06-28 15:37:02.518 FLO Cycling[21958:15e03] I've downloaded: 66542 bytes
2012-06-28 15:37:02.520 FLO Cycling[21958:15e03] currentlyReadingFeeds turned off
2012-06-28 15:37:02.521 FLO Cycling[21958:15e03] The RSSFeedData Object currently contains 104392 bytes
2012-06-28 15:37:02.645 FLO Cycling[21958:15e03] remote url returned 200 no error
2012-06-28 15:37:02.646 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:02.650 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:02.745 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:02.748 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:02.749 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:02.845 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:02.846 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:02.848 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:02.944 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:02.946 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:02.946 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:02.947 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:02.949 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:03.042 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:03.044 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:03.046 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:03.049 FLO Cycling[21958:15e03] Data Received
2012-06-28 15:37:03.050 FLO Cycling[21958:15e03] i = 4
2012-06-28 15:37:03.053 FLO Cycling[21958:15e03] RSSFeedArray = 4
2012-06-28 15:37:03.054 FLO Cycling[21958:15e03] I've downloaded: 76718 bytes
2012-06-28 15:37:03.055 FLO Cycling[21958:15e03] currentlyReadingFeeds turned off
2012-06-28 15:37:03.057 FLO Cycling[21958:15e03] The RSSFeedData Object currently contains 181110 bytes
2012-06-28 15:37:03.059 FLO Cycling[21958:15e03] I am parsing
2012-06-28 15:37:03.060 FLO Cycling[21958:15e03] Inside the Parsing call the RSSFeedData Object contains 181110 bytes
2012-06-28 15:37:03.062 FLO Cycling[21958:17803] In the parseRSSData method the RSSFeedData Object contains 181110 bytes
2012-06-28 15:37:03.063 FLO Cycling[21958:17803] The Parse methods is being called
2012-06-28 15:37:03.066 FLO Cycling[21958:17803] Title: Slowtwitch.com
2012-06-28 15:37:03.066 FLO Cycling[21958:17803] Title: Slowtwitch.com
2012-06-28 15:37:03.067 FLO Cycling[21958:17803] Title: The 2012 Celtman video
2012-06-28 15:37:03.068 FLO Cycling[21958:17803] Title: Derek Oskutis' dangerous life
2012-06-28 15:37:03.069 FLO Cycling[21958:17803] Title: Norseman bound Bjorn Andersson
2012-06-28 15:37:03.069 FLO Cycling[21958:17803] Title: S-Works Venge LTD EPS
2012-06-28 15:37:03.070 FLO Cycling[21958:17803] Title: Kienle, Wutti take Heilbronn
2012-06-28 15:37:03.071 FLO Cycling[21958:17803] Title: Van Lierde, Deckers rule Nice
2012-06-28 15:37:03.071 FLO Cycling[21958:17803] Title: Alistair Brownlee dominates again
2012-06-28 15:37:03.075 FLO Cycling[21958:17803] Title: Gambles, Naeth win Syracuse 70.3
2012-06-28 15:37:03.076 FLO Cycling[21958:17803] Title: Drew Scott wins Buffalo Springs Lake 70.3
2012-06-28 15:37:03.077 FLO Cycling[21958:17803] Title: Guillaume, Tisseyre win Mt. Tremblant
Take care,
Jon