I'm building an RSSfeed reader wherein there the task of parsing the xmldata gets delegated to two separate objects. As the xml tree is walked down, the actual parsing task is initiated with the RSSContent object, where the title of individual articles is generated by picking up appropriate strings of characters, and then moved to RSSContentArticle object, where the web links to the actual articles are pieced together character by character.
The job of delegation starts when the connection to the RSSfeed's webservice is established, and one ListViewController object is made a delegate of the NSXMLParser object. As the control flow reaches specific XML tags of interest, the job of parsing gets re-delegated to the next object, for instance- ListViewController->RSSContent->RSSContentArticle, and then gets moved back to the previous delegate as we keeping walking out of the nested element tags, one element at a time, like this- RSSContentArticle->RSSContent->ListViewController.
However, I'm currently facing a problem while trying to achieve this flow of parsing as I want to have it move from RSSContent to RSSContentArticle through re-delegation.
Here is the code-
ListViewController.h
#import
@class RSSChannel, WebViewController, RSSContent;
@interface ListViewController : UITableViewController<nsxmlparserdelegate,uitableviewdelegate, uitableviewdatasource,="" nsurlconnectiondatadelegate="">
{
NSURLConnection *connection;
NSMutableData *xmlData;
RSSChannel *channel;
NSMutableArray *contentCollection;
NSMutableString *currentString;
}
@property (nonatomic, strong) WebViewController *webViewController;
@property (nonatomic, strong) RSSContent *content;
@property (nonatomic, strong) NSMutableString *cellTitle;
-(void)fetchEntries;
@end
ListViewController.m
#import "ListViewController.h"
#import "RSSContent.h"
#import "RSSChannel.h"
#import "RSSContentArticle.h"
#import "RSSItem.h"
#import "WebViewController.h"
@interface ListViewController ()
@end
@implementation ListViewController
@synthesize webViewController, content;
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)io{
if ([[UIDevice currentDevice] userInterfaceIdiom]== UIUserInterfaceIdiomPad) {
return YES;
}
return io== UIInterfaceOrientationPortrait;
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
NSLog(@"ListViewcontroller init..%@ %@", self.tableView.dataSource, self.tableView.delegate);
[self fetchEntries];
contentCollection= [[NSMutableArray alloc] init];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
-(void)fetchEntries{
NSLog(@"%@", NSStringFromSelector(_cmd));
xmlData= [[NSMutableData alloc] init];
NSURL *url= [NSURL URLWithString:@"https://www.apple.com/pr/feeds/pr.rss"];
NSURLRequest *req= [NSURLRequest requestWithURL:url];
connection= [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];//self has been made NSURLConnection's delegate
}
-(void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data{
NSLog(@"%@", NSStringFromSelector(_cmd));
// Add the incoming chunk of data to the container we are keeping
// The data always comes in the correct order
[xmlData appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)conn{
NSLog(@"%@", NSStringFromSelector(_cmd));
// We are just checking to make sure we are getting the XML
NSString *xmlCheck= [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding];
NSLog(@"xmlCheck= %@",xmlCheck);
NSXMLParser *parser=[[NSXMLParser alloc] initWithData:xmlData];
[parser setDelegate:self];
NSLog(@"parsing initiated");
[parser parse];
xmlData=nil;
connection=nil;
[self.tableView reloadData];
WSLog(@"channel test- %@\n %@\n %@\n",channel, [channel title], [channel infoString]);
}
-(void)connection:(NSURLConnection *)conn didFailWithError:(NSError *)error{
connection=nil;
xmlData=nil;
NSString *errorString= [NSString stringWithFormat:@"Fetch failed: %@",[error localizedDescription]];
UIAlertView *av= [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
[av show];
}
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
NSLog(@"%@ found a %@ element", self, elementName);
if ([elementName isEqual:@"channel"]) { // element starts
// If the parser saw a channel, create a new object, have the ivar- 'channel' point to it.
channel= [[RSSChannel alloc] init];
// Give the channel object a pointer back to ourselves for later.
channel.parentParserDelegate= self;
// Set the parser's delegate to the channel object
// There will be a warning here, ignore it for now
parser.delegate= channel;
}
else if ([elementName isEqual:@"entry"]) {
content= [[RSSContent alloc] init];
// Give the content object a pointer back to ourselves for later.
content.parentParserDelegate= self;
parser.delegate= content;
[contentCollection addObject:content];
}
}
RSSContent.h
#import
@class RSSContentArticle;
@interface RSSContent : NSObject
{
NSMutableString *currentString;
}
@property (nonatomic, weak)id parentParserDelegate;
@property (nonatomic, strong)NSString *title;
@property (nonatomic, strong)NSString *link;
@property (nonatomic, strong)RSSContentArticle *article;
@end
RSSContent.m
#import "RSSContent.h"
#import "RSSContentArticle.h"
@implementation RSSContent
@synthesize parentParserDelegate, title, link, article;
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
NSLog(@"\t%@ found a %@ element",self,elementName);
if ([elementName isEqual:@"title"]) {
currentString= [[NSMutableString alloc] init];
title= currentString;
}
else if([elementName isEqual:@"content"]){
article= [[RSSContentArticle alloc] init];
parser.delegate= article;
article.parentParserDelegate= self;
}
}
-(void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock{
NSString *string= [[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
NSLog(@"\tfound CDATA within content- %@",string);
[currentString appendString:string];
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
NSLog(@"\tcontent ended");
currentString= nil;
if ([elementName isEqual:@"entry"]) {
parser.delegate= parentParserDelegate;
}
}
@end
RSSContentArticle.h
#import
@interface RSSContentArticle : NSObject
{
NSMutableString *currentString;
}
@property (nonatomic, weak)id parentParserDelegate;
@property (nonatomic, strong)NSString *link;
@end
RSSContentArticle.m
#import "RSSContentArticle.h"
@implementation RSSContentArticle
@synthesize link, parentParserDelegate;
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
NSLog(@"\t\t%@ found a %@ element",self,elementName);
if ([elementName isEqual:@"a"]) {
currentString= [[NSMutableString alloc] init];
link= currentString;
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
NSLog(@"\t\tfound character(s) within contentArticle- %@",string);
[currentString appendString:string];
NSLog(@"\t\tcurrentString- %@", currentString);
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
NSLog(@"\t\tcontent ended");
currentString= nil;
if ([elementName isEqual:@"content"]) {
parser.delegate= parentParserDelegate;
}
}
@end
When the code runs, the control does not flow through -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict in RSSContentArticle.m, meaning that the RSSContentArticle object does not get sent this message after the NSXMLParser having re-delegated parsing to the same in RSSContent.m file when the element name is "content". I have remained stuck with the issue for a while now. Can someone please look into this, advice me meaningfully on how to go about solving this issue. I'd be thankful.