I am using a tab bar application, and there are 4 different table views. There are four tab bar items and each has a different table view. I should populate arrays form .xml files. Yet, problem is this:
I can parse only one XML file at a time. How can I parse two or more .xml files at the same time by NSXMLParser?
Or should I merge the xml files? Yet, if I merge, I have to create two or moreNSMutableArray`s to put those into another tableview views. Any suggestion?
What do you guys suggest? I do not know how to merge those xml files, but even if I do, I should create NSMutableArrays to use those to populate arrays for each view.
Thanks in advance.
Edit:
This is my AppDelegate.m
#synthesize window = _window;
#synthesize tabBarController = _tabBarController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
//Initialize the delegate.
XMLParser *parser = [[XMLParser alloc] initXMLParser];
// Configure and show the window
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
[window makeKeyAndVisible];
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Save data if appropriate
}
- (void)dealloc {
[tabBarController release];
[window release];
[super dealloc];
}
#end
This is my XMLparser.m:
#import "XMLParser.h"
#import "XMLAppDelegate.h"
#import "Duyuru.h"
#import "Beste.h"
#import "BesteViewController.h"
#import "DuyuruViewController.h"
#implementation XMLParser
- (XMLParser *) initXMLParser {
[super init];
appDelegate = (XMLAppDelegate *)[[UIApplication sharedApplication] delegate];
return self;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if (parser == bestevc.parser ) {
if([elementName isEqualToString:#"Besteler"]) {
//Initialize the array.
bestevc.besteler = [[NSMutableArray alloc] init];
}
else if([elementName isEqualToString:#"Beste"]) {
//Initialize the book.
aBeste = [[Beste alloc] init];
//Extract the attribute here.
aBeste.besteID = [[attributeDict objectForKey:#"id"] integerValue];
NSLog(#"Reading id value :%i", aBeste.besteID);
}
}
if (parser == duyuruvc.parser ) {
if([elementName isEqualToString:#"Duyurular"]) {
//Initialize the array.
duyuruvc.duyurular = [[NSMutableArray alloc] init];
}
else if([elementName isEqualToString:#"Duyuru"]) {
//Initialize the book.
aDuyuru = [[Duyuru alloc] init];
//Extract the attribute here.
aDuyuru.duyuruID = [[attributeDict objectForKey:#"id"] integerValue];
NSLog(#"Reading id value :%i", aDuyuru.duyuruID);
}
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (parser == bestevc.parser ) {
if(!currentElementValue1)
currentElementValue1 = [[NSMutableString alloc] initWithString:string];
else
[currentElementValue1 appendString:string];
NSLog(#"Processing Value: %#", currentElementValue1);
}
if (parser == duyuruvc.parser ) {
if(!currentElementValue2)
currentElementValue2 = [[NSMutableString alloc] initWithString:string];
else
[currentElementValue2 appendString:string];
NSLog(#"Processing Value: %#", currentElementValue2);
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if (parser == bestevc.parser) {
if([elementName isEqualToString:#"Besteler"])
return;
//There is nothing to do if we encounter the Books element here.
// and release the object.
if([elementName isEqualToString:#"Beste"]) {
[bestevc.besteler addObject:aBeste];
[aBeste release];
aBeste = nil;
}
else
[aDuyuru setValue:currentElementValue1 forKey:elementName];
[currentElementValue1 release];
currentElementValue1 = nil;
}
if (parser == duyuruvc.parser) {
if([elementName isEqualToString:#"Duyurular"])
return;
//There is nothing to do if we encounter the Books element here.
// and release the object.
if([elementName isEqualToString:#"Duyuru"]) {
[duyuruvc.duyurular addObject:aDuyuru];
[aDuyuru release];
aDuyuru = nil;
}
else
[aDuyuru setValue:currentElementValue2 forKey:elementName];
[currentElementValue2 release];
currentElementValue2 = nil;
}
}
- (void) dealloc {
[aDuyuru release];
[aBeste release];
[currentElementValue1 release];
[currentElementValue2 release];
[super dealloc];
}
#end
This is my BesteViewController.m:
#import "BesteViewController.h"
#import "XMLAppDelegate.h"
#import "Beste.h"
#import "XMLParser.h"
#implementation BesteViewController
#synthesize parser, besteler;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)
section {
return [besteler count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath
(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier:CellIdentifier] autorelease];
}
Beste *aBeste = [besteler objectAtIndex:indexPath.row];
[[cell textLabel] setText:aBeste.name];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
// Set up the cell
return cell;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Uncomment the following line to add the Edit button to the navigation bar.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
appDelegate = (XMLAppDelegate *)[[UIApplication sharedApplication] delegate];
NSURL *url = [[NSURL alloc]
initWithString:#"https://sites.google.com/site/bfbremoteser
ver/iphoneapp/besteler.xml"];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
//Initialize the delegate.
XMLParser *parser = [[XMLParser 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!!!");
self.navigationItem.title = #"Besteler";
}
/*
// Override to support rearranging the list
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath
*)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
}
*/
/*
// Override to support conditional rearranging of the list
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath*)
indexPath {
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
/*
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
*/
/*
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
*/
/*
- (void)viewWillDisappear:(BOOL)animated {
}
*/
/*
- (void)viewDidDisappear:(BOOL)animated {
}
*/
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)dealloc {
[besteler release];
[appDelegate release];
[super dealloc];
}
#end
I'm not sure I understood your question correctly, so please try to provide more details and I'll edit my answer if needed.
You should have a separate NSXMLParser instance for every xml file you want to parse. In your case there should probably be one NSXMLParser instance in each of the view controllers on your tab bar.
You can start them all even with the same NSXMLParserDelegate for all of them because all delegate methods tell you which NSXMLParser instance called them.
Edit:
You should move this code to the view controllers on your tab bar controller:
NSURL *url = [[NSURL alloc] initWithString:#"..."];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
//Initialize the delegate.
XMLParser *parser = [[XMLParser 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!!!");
except this line (keep it in appdelegate and pass a reference to it into all the view controllers on your tab bar controller that need to parse something):
XMLParser *parser = [[XMLParser alloc] initXMLParser];
Then set a parser (the NSXMLParser instance) as a property on your view controllers and inside xmlParse check wich of the parsers called the delegate and act accordingly. For example:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if (parser == firstViewController.parser) {
// first tab called this parser delegate method, insert code to parse it here
} else if (parser == firstViewController.parser) {
// second...and so on
}
}
Related
I am trying to implement an rss reader into a table inside a container. I have the code of the parser in an other project and in the specific project it works fine without any error. I copied every file, 4 files exactly as they are in the other project and i copied also the view controllers into my storyboard so they are exactly the same. But when i run the code i get an error!
here is a pic with my error.
I don't know why is this happening. In the other project which has only two view controllers with the table view and the web view it works fine. But when i try to copy every file as it is into my other project I get this error.
This is my .m file
#import "APPMasterViewController.h"
#import "APPDetailViewController.h"
#interface APPMasterViewController () {
NSXMLParser *parser;
NSMutableArray *feeds;
NSMutableDictionary *item;
NSMutableString *title;
NSMutableString *link;
NSString *element;
}
#end
#implementation APPMasterViewController
(void)awakeFromNib {
[super awakeFromNib];
}
- (void)viewDidLoad {
[super viewDidLoad];
feeds = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:#"http://radioevros.gr/feed/"];
parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[parser setDelegate:self];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return feeds.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = [[feeds objectAtIndex:indexPath.row] objectForKey: #"title"];
return cell;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI: (NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
element = elementName;
if ([element isEqualToString:#"item"]) {
item = [[NSMutableDictionary alloc] init];
title = [[NSMutableString alloc] init];
link = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"item"]) {
[item setObject:title forKey:#"title"];
[item setObject:link forKey:#"link"];
[feeds addObject:[item copy]];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if ([element isEqualToString:#"title"]) {
[title appendString:string];
} else if ([element isEqualToString:#"link"]) {
[link appendString:string];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
[self.tableView reloadData];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSString *string = [feeds[indexPath.row] objectForKey: #"link"];
[[segue destinationViewController] setUrl:string];
}
}
-(void) viewDidUnload{
[element release];
element = nil;
[super viewDidUnload];
}
- (void)dealloc {
[element release];
[super dealloc];
}
#end
I can't say for certain since I haven't tried running your code, but you may want to try to store element using element = [elementName copy]; instead and see if that gets rid of the exception.
My guess is that elementName gets deallocated after you exit the method since it is only a local parameter variable.
As a side note, it appears that you are doing manual memory management. I highly suggest that you convert your project to use ARC since it not only streamlines memory management, it is also what Apple has been recommending to use for quite a while now.
This question already exists:
UIRefreshControl not refreshing xml data
Closed 9 years ago.
Can anyone explain why my pull to refresh isn't working? I've called the UIRefresh controller and the "pull to refresh" animation works but the table view doesn't reload the XML data. What am I doing wrong? Please help.
#import "MasterViewController.h"
#import "DetailViewController.h"
#interface MasterViewController () {
NSXMLParser *parser;
NSMutableArray *feeds;
NSMutableDictionary *item;
NSMutableString *title;
NSMutableString *link;
NSString *element;
}
#end
#implementation MasterViewController
- (void)awakeFromNib {
[super awakeFromNib];
}
// Paste Blog feed here
- (void)viewDidLoad {
[super viewDidLoad];
feeds = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:#"http://www.placeholder.xml"];
parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[parser setDelegate:self];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
UIRefreshControl *refreshControl = [UIRefreshControl new];
[refreshControl addTarget:self
action:#selector(refresh:)
forControlEvents:UIControlEventValueChanged];
refreshControl.attributedTitle =
[[NSAttributedString alloc] initWithString:#"Pull to refresh..."];
self.refreshControl = refreshControl;
}
- (void)refresh:(UIRefreshControl *)sender {
// ... your refresh code
NSURL *url = [NSURL URLWithString:#"http://www.placeholder.xml"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
(void)[[NSURLConnection alloc] initWithRequest:request delegate:self];
[sender endRefreshing];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return feeds.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:#"Cell"
forIndexPath:indexPath];
cell.textLabel.text =
[[feeds objectAtIndex:indexPath.row] objectForKey:#"title"];
return cell;
}
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict {
element = elementName;
if ([element isEqualToString:#"item"]) {
item = [[NSMutableDictionary alloc] init];
title = [[NSMutableString alloc] init];
link = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"item"]) {
[item setObject:title forKey:#"title"];
[item setObject:link forKey:#"link"];
[feeds addObject:[item copy]];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if ([element isEqualToString:#"title"]) {
[title appendString:string];
} else if ([element isEqualToString:#"link"]) {
[link appendString:string];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
[self.tableView reloadData];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSString *string = [feeds[indexPath.row] objectForKey:#"link"];
[[segue destinationViewController] setUrl:string];
}
}
#end
The idea presented in the answer here should help: stackoverflow.com/a/16347259/1151545
Basically create ur UIRefreshControl then add it as a subview to any UIScrollView. FYI the UITableView is a subclass of UIScrollView
I'm pretty new iPhone development and i have a problem.
After several hours of searching and digging in the code I could understand the source of the problem (hope) but do not know how to solve it.
the problem is that the tableView cells loads before the parser is finish so the "[array count]" is nil.
When I set the 'number of rows in section' manually, the table does appear, but only after a few sec and scrolling up and down.
i have 2 classes, one for XMLParser and one for show the tableView.
According to what I read before I opened this question is that i need to reload the tavleview data but becuase i have 2 various classes i dont know how to do that.
any ideas?
Thanks in davance!
here is my XMLParser code:
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
self.titles = [[NSMutableArray alloc]init];
self.descriptions = [[NSMutableArray alloc]init];
self.links = [[NSMutableArray alloc]init];
self.pubDate = [[NSMutableArray alloc]init];
}
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
}
BOOL isItem = NO;
BOOL isTitle = NO;
BOOL isDesription = NO;
BOOL isImg = NO;
BOOL isPubDate = NO;
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:#"item"]) {
isItem = YES;
}
if ([elementName isEqualToString:#"title"]) {
isTitle=YES;
self.titlesString = [[NSMutableString alloc]init];
}
if ([elementName isEqualToString:#"description"]) {
isDesription = YES;
self.descriptionString = [[NSMutableString alloc]init];;
self.data = [NSMutableData data];
}
if ([elementName isEqualToString:#"pubDate"]) {
isPubDate = YES;
self.pubDateString = [[NSMutableString alloc]init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if(isItem && isTitle){
[self.titlesString appendString:string];
}
if (isItem && isDesription) {
[self.descriptionString appendString:string];
}
if (isItem && isPubDate) {
[self.pubDateString appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
{
if (self.data)
[self.data appendData:CDATABlock];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"item"]) {
isItem = NO;
[self.titles addObject:self.titlesString];
[self.descriptions addObject:self.descriptionString];
[self.pubDate addObject:self.pubDateString];
NSLog(#"%#,%#,%#,",self.titlesString,self.descriptionString,self.pubDate);
}
if ([elementName isEqualToString:#"title"]) {
isTitle=NO;
}
if ([elementName isEqualToString:#"description"]) {
isDesription = NO;
if ([self.data length] > 0)
{
NSString *htmlSnippet = [[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding];
NSString *imageSrc = [self firstImgUrlString:htmlSnippet];
[self.links addObject:imageSrc];
}
self.data = nil;
}
if([elementName isEqualToString:#"pubDate"])
isPubDate = NO;
}
- (NSString *)firstImgUrlString:(NSString *)string
{
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"(<img\\s[\\s\\S]*?src\\s*?=\\s*?['\"](.*?)['\"][\\s\\S]*?>)+?"
options:NSRegularExpressionCaseInsensitive
error:&error];
NSTextCheckingResult *result = [regex firstMatchInString:string
options:0
range:NSMakeRange(0, [string length])];
if (result)
return [string substringWithRange:[result rangeAtIndex:2]];
return nil;
}
and here's my show tableView code:
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"menuButton.png"] style:UIBarButtonItemStyleBordered target:self.viewDeckController action:#selector(toggleLeftView)];
NSURL *url;
if (!self.isGetLink)
url = [NSURL URLWithString:#"http://www.ynet.co.il/Integration/StoryRss2.xml"];
else
url = [NSURL URLWithString:self.linkForParsingString];
if (!self.xmlParser) {
self.xmlParser = [[XMLparser alloc]init];
[self.xmlParser LoadXMLWithURl:url];
}
self.isGetLink = NO;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier
{
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.xmlParser.titles count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CustomCell";
CustomCell *cell = (CustomCell*) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.lblTitle.text = [self.xmlParser.titles objectAtIndex:indexPath.row];
cell.lblTitle.font = [UIFont boldSystemFontOfSize:[UIFont systemFontSize]];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[self.xmlParser.links objectAtIndex:indexPath.row]]];
cell.imgView.image = [UIImage imageWithData:data];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 82;
}
#pragma mark - Table view delegate
NSString *curnentDes;
NSString *currentTitle;
NSString *currentPubDate;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ReadViewController *rvc = [[ReadViewController alloc]initWithNibName:#"ReadViewController" bundle:nil];
curnentDes = [self.xmlParser.descriptions objectAtIndex:indexPath.row];
currentTitle = [self.xmlParser.titles objectAtIndex:indexPath.row];
currentPubDate = [self.xmlParser.pubDate objectAtIndex:indexPath.row];
NSDateFormatter *inputFormatter = [[NSDateFormatter alloc]init];
[inputFormatter setDateFormat:#"EEE, dd MMM yyyy HH:mm:ss Z"];
NSDate *inputDate = [inputFormatter dateFromString:currentPubDate];
NSDateFormatter *outputFormatter = [[NSDateFormatter alloc]init];
[outputFormatter setDateFormat:#"dd/MM/yyyy HH:mm"];
NSString *outputDate = [outputFormatter stringFromDate:inputDate];
rvc.description = curnentDes;
rvc.stitle = currentTitle;
rvc.pubDate = outputDate;
[self.navigationController pushViewController:rvc animated:YES];
}
Pretty simple reload the table after your parsing is done, you are good to go. The reason your data comes after scrolling is your array is updated at a later point and then cellForRowAtIndex is called and array has content so you see rows.
Note: cellForRow is called for every row (hope you know that).
Using notification:
In your parser class
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
[[NSNotificationCenter defaultCenter ]postNotificationName:#"parsingComplete" object:nil];
}
In ViewDidLoad of your table view class add this code and add the other functions anywhere in ur class:
your viewDidLoad(edited)
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(parsingComplete) name:#"parsingComplete" object:nil];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"menuButton.png"] style:UIBarButtonItemStyleBordered target:self.viewDeckController action:#selector(toggleLeftView)];
NSURL *url;
if (!self.isGetLink)
url = [NSURL URLWithString:#"http://www.ynet.co.il/Integration/StoryRss2.xml"];
else
url = [NSURL URLWithString:self.linkForParsingString];
if (!self.xmlParser) {
self.xmlParser = [[XMLparser alloc]init];
[self.xmlParser LoadXMLWithURl:url];
}
self.isGetLink = NO;
}
//Function to handle notification:
-(void)parsingComplete
{
NSLog(#"parsing results: %#",self.xmlParser.titles);
//change your tableViewName
[yourTableView reloadData];
}
//removing notification:
-(void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Reload the table once parsing is completed. Use delegate methods to reload the table view from didEndElement method. Try some think like this.
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:#"Final Element"])
{
// Reload your table View using delegates
}
}
I am trying to load a youtube channel's feed into a uitableview with an rss feed. I need this to display the thumbnail from the individual videos. I can only find this using the gdata client which does not work. Here is the code I have so far:
Videos.h:
#import <UIKit/UIKit.h>
#interface Videos : UITableViewController<NSXMLParserelegate>{
IBOutlet UITableView * newsTable;
UIActivityIndicatorView * activityIndicator;
CGSize cellSize;
NSXMLParser * rssParser;
NSMutableArray * stories;
// a temporary item; added to the "stories" array one at a time, and cleared for the next one
NSMutableDictionary * item;
// it parses through the document, from top to bottom...
// we collect and cache each sub-element value, and then save each item to our array.
// we use these to track each current item, until it's ready to be added to the "stories" array
NSString * currentElement;
NSMutableString * currentTitle, * currentDate, * currentSummary, * currentLink;
}
- (void)parseXMLFileAtURL:(NSString *)URL;
#end
Videos.m
#import "Videos.h"
#import "AppDelegate.h"
#implementation Videos
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
self.tabBarItem.image = [UIImage imageNamed:#"clapboard#2x.png"];
}
return self;
}
- (void)viewDidLoad {
// Add the following line if you want the list to be editable
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [stories count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
}
// Set up the cell
int storyIndex = [indexPath indexAtPosition: [indexPath length] - 1];
cell.textLabel.text=[[stories objectAtIndex: storyIndex] objectForKey: #"title"];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic
int storyIndex = [indexPath indexAtPosition: [indexPath length] - 1];
NSString * storyLink = [[stories objectAtIndex: storyIndex] objectForKey: #"link"];
NSLog(#"%#",stories );
// clean up the link - get rid of spaces, returns, and tabs...
storyLink = [storyLink stringByReplacingOccurrencesOfString:#" " withString:#""];
storyLink = [storyLink stringByReplacingOccurrencesOfString:#"\n" withString:#""];
storyLink = [storyLink stringByReplacingOccurrencesOfString:#" " withString:#""];
// open in Safari
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:storyLink]];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if ([stories count] == 0) {
NSString * path = #"https://youtube.com/rss/user/TheGruenebergBrother/videos.rss";
[self parseXMLFileAtURL:path];
}
cellSize = CGSizeMake([newsTable bounds].size.width, 60);
}
- (void)viewWillDisappear:(BOOL)animated {
}
- (void)viewDidDisappear:(BOOL)animated {
}
#pragma mark - parseing_Delegate_methods
- (void)parserDidStartDocument:(NSXMLParser *)parser{
NSLog(#"found file and started parsing");
}
- (void)parseXMLFileAtURL:(NSString *)URL
{
stories = [[NSMutableArray alloc] init];
//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
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)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];
}
- (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:#"item"]) {
// 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];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
//NSLog(#"ended element: %#", elementName);
if ([elementName isEqualToString:#"item"]) {
// save values to an item, then store that item into the array...
[item setObject:currentTitle forKey:#"title"];
[item setObject:currentLink forKey:#"link"];
[item setObject:currentSummary forKey:#"summary"];
[item setObject:currentDate forKey:#"date"];
[stories addObject:[item copy]];
NSLog(#"adding story: %#", currentTitle);
}
}
- (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];
} 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];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)dealloc {
[currentElement release];
[rssParser release];
[stories release];
[item release];
[currentTitle release];
[currentDate release];
[currentSummary release];
[currentLink release];
[super dealloc];
}
#end
Also where should the code go, and what is the code?
Thanks
there is a thumbnail url,
http://img.youtube.com/vi/VIDEOIDHERE/0.jpg
http://img.youtube.com/vi/VIDEOIDHERE/1.jpg
http://img.youtube.com/vi/VIDEOIDHERE/2.jpg
http://img.youtube.com/vi/VIDEOIDHERE/3.jpg
will fetch you the thumbnail for any video. The number represents the quality, zero being the highest. E.g:
http://img.youtube.com/vi/F2Jko4Ipdrs/0.jpg
The goal of my application is to parse some XML, display one element of the xml in a tableview and then have the user click on the cell, and it pushes to a new table view where the rest of the data for that element is displayed. The first table view that displays only the list works fine, but for some reason I can't get the push to a new view controller to work. Below is the code I am using. The first view controller displays in a table view; currentCallType. I wan the user to be be able to click on that table cell, then push to a new table view where it displays the units, station and location. Any help would be AWESOME! thanks.
View controller for first tableview:
#import "ThirdViewController.h"
#import "UnitsXMLParser.h"
#import "DetailViewController"
#implementation ThirdViewController
#synthesize unitsTableView;
#synthesize currentCallType, station, location, units;
XMLParser1 *xmlParser;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[xmlParser units] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
Units *currentCall = [[xmlParser units] objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// Set up the cell...
cell.textLabel.text = [currentCall currentCallType];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 55;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailViewController *detail = [self.storyboard instantiateViewControllerWithIdentifier:#"detail"];
[self.navigationController pushViewController:detail animated:YES];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
xmlParser = [[XMLParser1 alloc] loadXMLByURL:#"http://localhost:8888/units.xml"];
}
XML Parser:
#import <Foundation/Foundation.h>
#import "UnitsXMLParser.h"
#implementation XMLParser1
#synthesize units = _units;
NSMutableString *currentNodeContent;
NSXMLParser *parser;
Units *currentCall;
bool isStatus;
-(id) loadXMLByURL:(NSString *)urlString
{
_units = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
return self;
}
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentNodeContent = (NSMutableString *) [string stringByReplacingOccurrencesOfString:#"~" withString:#""];
}
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementname isEqualToString:#"station"])
{
currentCall = [Units alloc];
isStatus = YES;
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI: (NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if (isStatus)
{
if ([elementname isEqualToString:#"units"])
{
currentCall.units = currentNodeContent;
}
if ([elementname isEqualToString:#"name"])
{
currentCall.currentCallType = currentNodeContent;
}
if ([elementname isEqualToString:#"stationid"])
{
currentCall.station = currentNodeContent;
}
if ([elementname isEqualToString:#"address"])
{
currentCall.location = currentNodeContent;
}
}
if ([elementname isEqualToString:#"station"])
{
[self.units addObject:currentCall];
currentCall = nil;
currentNodeContent = nil;
}
}
#end
A longshot; but do you have your project configured to use a UINavigationController ? Your view controllers will not be contained in / managed by a UINavigationController unless you start with the correct project template or manually add the UINavigationController . If the view controller containing your posted code is not backed by a navigation controller, [self.navigationController pushViewController:detail animated:YES] will do nothing.
Also, make sure that you have hooked up your UITableViewDelegate in addition to your UITableViewDataSource , so that your code will catch the row selection.
I only ask because you do not explicitly state that you have set up your project to use a UINavigationController or confirm that you have hooked up both the delegate and datasource in Interface Builder.