I am trying to show parsed Yahoo RSS feed on the table view. But nothing is getting shown on the screen. When I used breakpoints I came to know that the control is not going to cellForRowAtIndexPath method at all. I don't know why that is happening. The structure of the yahoo feed is as follows:
<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
<channel>
<title>Yahoo! News - Latest News & Headlines</title>
<link>http://news.yahoo.com/</link>
<description>The latest news and headlines from Yahoo! News. Get breaking news stories and in-depth coverage with videos and photos.</description>
<language>en-US</language>
<copyright>Copyright (c) 2013 Yahoo! Inc. All rights reserved</copyright>
<pubDate>Sun, 21 Apr 2013 17:08:00 -0400</pubDate>
<ttl>5</ttl>
<image>
<title>Yahoo! News - Latest News & Headlines</title>
<link>http://news.yahoo.com/</link>
<url>http://l.yimg.com/a/i/us/nws/th/main_142c.gif</url>
</image>
<item><title>After the bombings, the blame game begins</title><description><p><a href="http://news.yahoo.com/boston-marathon-bombing-blame-game-begins-210800101.html"><img src="http://l3.yimg.com/bt/api/res/1.2/uiv31afw5K_BzPxeYQz44Q--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-04-22T013026Z_741208741_GM1E94M0Q7101_RTRMADP_3_USA-EXPLOSIONS-BOSTON.JPG" width="130" height="86" alt="A couple embraces at a memorial on Boylston Street to the victims of the Boston Marathon bombings in Boston" align="left" title="A couple embraces at a memorial on Boylston Street to the victims of the Boston Marathon bombings in Boston" border="0" /></a>Some lawmakers fault the FBI for not following up on intelligence about one of the alleged bombers.</p><br clear="all"/></description><link>http://news.yahoo.com/boston-marathon-bombing-blame-game-begins-210800101.html</link><pubDate>Sun, 21 Apr 2013 17:08:00 -0400</pubDate><source url="http://www.csmonitor.com/">Christian Science Monitor</source><guid isPermaLink="false">boston-marathon-bombing-blame-game-begins-210800101</guid><media:content url="http://l3.yimg.com/bt/api/res/1.2/uiv31afw5K_BzPxeYQz44Q--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-04-22T013026Z_741208741_GM1E94M0Q7101_RTRMADP_3_USA-EXPLOSIONS-BOSTON.JPG" type="image/jpeg" width="130" height="86"></media:content><media:text type="html"><p><a href="http://news.yahoo.com/boston-marathon-bombing-blame-game-begins-210800101.html"><img src="http://l3.yimg.com/bt/api/res/1.2/uiv31afw5K_BzPxeYQz44Q--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9ODU7dz0xMzA-/http://media.zenfs.com/en_us/News/Reuters/2013-04-22T013026Z_741208741_GM1E94M0Q7101_RTRMADP_3_USA-EXPLOSIONS-BOSTON.JPG" width="130" height="86" alt="A couple embraces at a memorial on Boylston Street to the victims of the Boston Marathon bombings in Boston" align="left" title="A couple embraces at a memorial on Boylston Street to the victims of the Boston Marathon bombings in Boston" border="0" /></a>Some lawmakers fault the FBI for not following up on intelligence about one of the alleged bombers.</p><br clear="all"/></media:text><media:credit role="publishing company"></media:credit></item></guid></channel>
</rss>
My feedViewController.m is as follows:
#interface feedViewController ()
#end
#implementation feedViewController
#synthesize tableView,showPosts;
//#synthesize feed;
Feed *xmlParseFeed;
//channel *chShow;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//self.feed = [[Feed alloc] init];
self.showPosts = [[NSMutableArray alloc] init];
NSArray *newPosts = [xmlParseFeed newPosts];
if (newPosts) {
[self.showPosts addObjectsFromArray:newPosts];
//[newPosts release];
}
static NSString *feedURLString = #"http://news.yahoo.com/rss";
NSURL *feedURL = [NSURL URLWithString:feedURLString];
xmlParseFeed = [[Feed alloc] initWithURL:feedURL];
self.showPosts = [[NSMutableArray alloc] init];
[xmlParseFeed refresh];
}
- (void)viewDidUnload
{
[self setTableView:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return [showPosts count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
ItemDataCollection *post = [showPosts objectAtIndex:indexPath.row];
Feed *entry = [showPosts objectAtIndex:indexPath.row];
// Set up the cell...
channel *channelRecord = [self.showPosts objectAtIndex:indexPath.row];
cell.textLabel.text = channelRecord.cTitle;
cell.textLabel.text = channelRecord.pubDate;
NSLog(#"channelRecord.title *****************%#",channelRecord.cTitle);
/* cell.textLabel.text = post.title;
cell.textLabel.text = post.itemDescription;
cell.textLabel.text = post.titleImage;
NSLog(#"item title******%#",post.title); */
cell.textLabel.font=[UIFont fontWithName:#"Arial" size:12];
cell.textLabel.numberOfLines = 1;
return cell;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
Properties in channel class are: cTitle,pubDate and itemCollectionArray. Properties in Post class are: title, itemDescription and titleImage. Feed class is for parsing. the contents of Feed.m is as follows:
#class ItemDataCollection;
#implementation Feed
#synthesize feedURL,feedRequest,currentElement,currentElementData;
//#synthesize feedChannel;
//#synthesize feedPosts;
static ItemDataCollection *itemCollection;
static NSMutableArray *channelCollection;
NSMutableString *mString;
NSMutableString *str;
channel *Channel ;
- (NSArray *)newPosts {
NSMutableArray *posts = [[NSMutableArray alloc] init];
for (NSInteger item = 1; item <= 5; item++) {
//NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
ItemDataCollection *newPost;
newPost = [[ItemDataCollection alloc] init];
// NSString *pubDate = [NSDate dateWithTimeIntervalSinceNow:#"pubDate"];
newPost.title = [NSString stringWithFormat:#"title %#", kTitleElementName];
newPost.itemDescription = [NSString stringWithFormat:#"itemdescription %#", kItemDescription];
newPost.titleImage = [NSString stringWithFormat:#"image %#",kItemImage];
// newPost.itemTitle = [NSString stringWithFormat:#"itemtitle %#", ITEM_TITLE_XML];
[posts addObject:newPost];
//[newPost release];
// [pool drain];
}
return posts;
}
- (Feed *) initXMLParser {
//[super init];
appDelegate = (appAppDelegate *)[[UIApplication sharedApplication] delegate];
return self;
}
-(id)initWithURL:(NSURL *)sourceURL {
if (self = [super init]) {
self.feedURL = sourceURL;
channelCollection=[[NSMutableArray alloc] init];
}
return self;
}
- (void)refresh {
self.feedRequest = [ASIHTTPRequest requestWithURL:feedURL];
// [feedPosts removeAllObjects];
[feedRequest setDelegate:self];
[feedRequest startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request {
NSData *responseData = [request responseData];
// NSLog(#"*************response are *********%#",[[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]);
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:responseData];
[parser setDelegate:self];
if ([parser parse]) {
[[NSNotificationCenter defaultCenter]
postNotificationName:#"myevent"
object:nil];
// [posts ]
}
}
- (void)requestFailed:(ASIHTTPRequest *)request {
NSError *error = [request error];
NSLog(#"requestFailed: %#", [error localizedDescription]);
}
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict {
if ([elementName isEqualToString:kChannelElementName]) {
Channel = [[channel alloc] init];
dict=[[NSMutableDictionary alloc] init];
[Channel setItemCollectionArray:[[NSMutableArray alloc] init]];
return ;
}
if ([elementName isEqualToString:kItemElementName]) {
itemCollection=[[ItemDataCollection alloc] init];
return ;
}
if ([elementName isEqualToString:kTitleElementName]) {
return ;
}
if([elementName isEqualToString:kItemDescription]){
return ;
}
if ([elementName isEqualToString:kItemImage]) {
NSString *urlString = attributeDict[#"url"];
if(urlString){
[dict setObject:urlString forKey:#"img"];
NSLog(#"%#",urlString);
mString = [NSString stringWithFormat:urlString];
str = [NSString stringWithFormat:mString];
}
return ;
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (currentElementData == nil) {
self.currentElementData = [[NSMutableString alloc] init];
}
[currentElementData appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:kChannelElementName]) {
[channelCollection addObject:Channel];
NSLog(#"channel are***********%#",channelCollection);
for(ItemDataCollection *mydata in Channel.itemCollectionArray){
NSLog(#"___%# <><><><><> desc \n <><><><><><> img \n %#",mydata.title,/*mydata.itemDescription*/mydata.titleImage);
}
Channel =nil;
}
else if ([elementName isEqualToString:kItemElementName]) {
[[Channel itemCollectionArray] addObject:itemCollection];
itemCollection=nil;
}
else if ([elementName isEqualToString:kTitleElementName]) {
if(itemCollection==nil){
Channel.cTitle=currentElementData;
}
else{
itemCollection.title=currentElementData;
}
}
else if ([elementName isEqualToString:kPubDate]) {
Channel.pubDate=currentElementData;
}
else if ([elementName isEqualToString: kItemDescription]) {
if(itemCollection!=nil){
itemCollection.itemDescription = currentElementData;
}
}
else if([currentElementData rangeOfString:#"media:content"].location){
if(itemCollection!=nil){
if([str isEqualToString:mString]){
// [currentElementData appendString:dict];
itemCollection.titleImage = mString;
} else{
itemCollection.titleImage = #"";
}
}
}
self.currentElementData = nil;
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
NSString *info = [NSString stringWithFormat:
#"Error %i, Description: %#, Line: %i, Column: %i",
[parseError code],
[[parser parserError] localizedDescription],
[parser lineNumber],
[parser columnNumber]];
NSLog(#"RSS Feed Parse Error: %#", info);
}
#end
The feed is getting parsed and can be seen on the console. But it is not visible on the screen. What can be the reason? As i said earlier, cellForRowAtIndexPath() is not getting accessed at all. What's the reason for that??
I've added this method:
- (void)feedChanged:(NSNotification *)notification {
NSArray *newPosts = [xmlParseFeed newPosts];
NSLog(#"%#",newPosts);
if (newPosts) {
[self.showPosts addObjectsFromArray:newPosts];
[self.tableView reloadData];
// [self updateViewTitle];
// [newPosts release];
}
I don't see where in your code you're calling reloadData from UITableView. You need to call this method after you load newPosts.
If this doesn't work, check a couple of things like:
What is the value returned by tableView:numberOfRowsInSection:? Is it greater than zero? If it's zero, that's why tableView:cellForRowAtIndexPath doesn't get called.
How do you load your feed? Is it in the main thread or different thread? You should be loading it in a different thread, so you won't block your UI while you load the data, but make sure you're calling reloadData after the data is loaded into newPosts.
Related
i have a huge huge problem, i feel like i will never get rid of it. i got a xml file coming from my server, parsing it well. but i got duplicates in that xml file. The thing is i need to get rid of the duplicates in my NSMutableArray, in order to know what i have in my NSMutable array and display a little menu with wich section is avaible and wich is not. But i can't manage to copy only the good stuff into another array since the NSMutableArray is as a matter of fact a Array of dictionaries. And i don't know how to manage them, i tried sevral things the past two days with no results, so please if someone can help me it would very appreciated.
here is my entire code (hope it doesn't burn you eyes :3) :
#include <CommonCrypto/CommonDigest.h>
#include <CommonCrypto/CommonHMAC.h>
#import "SizingDataViewController.h"
#import "LCYDataBackedTableView.h"
#implementation SizingDataViewController
- (void)viewDidLoad {
//Add the following line if you want the list to be editable
self.title = #"Last choice";
}
-(BOOL)ifStringExists:(NSString *)stringSentToCheck{
for (int i = 0; i < ([stories count]); i++) {
NSLog(#"i = %i", i);
NSMutableString *stringToCheck = (NSMutableString *)[[stories objectAtIndex: i] objectForKey: #"type"];
if ([stringToCheck isEqualToString:stringSentToCheck] == YES) {
NSLog(#"%#", #"okay its OKAY ");
return YES;
}
}
return NO;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] autorelease];
CGRect frame = CGRectMake(0, 0, 160, 50);
UILabel *lbl1 = [[UILabel alloc] initWithFrame:frame];
lbl1.textAlignment = NSTextAlignmentRight;
[lbl1 setFont:[UIFont fontWithName:#"Helvetica" size:12.0]];
[lbl1 setTextColor:[UIColor grayColor]];
int storyIndex = [indexPath indexAtPosition: [indexPath length] - 1];
lbl1.text = [[stories objectAtIndex: storyIndex] objectForKey: #"creation_date"];//Modifier pour changer le texte affiché
[cell.contentView addSubview:lbl1];
[lbl1 release];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [stories count];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
- (void)parseXMLFileAtURL:(NSString *)URL
{
stories = [[NSMutableArray alloc] init];
NSData *xmlData = [URL dataUsingEncoding:NSUTF8StringEncoding];
rssParser = [[[NSXMLParser alloc] initWithData:xmlData]autorelease];
[rssParser setDelegate:self];
[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{
currentElement = [elementName copy];
if ([elementName isEqualToString:#"data"]) {
item = [[NSMutableDictionary alloc] init];
currentData_id = [[NSMutableString alloc] init];
currentSizing_id = [[NSMutableString alloc] init];
currentName = [[NSMutableString alloc] init];
currentSize = [[NSMutableString alloc] init];
currentType = [[NSMutableString alloc]init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"data"]) {
[item setObject:currentData_id forKey:#"data_id"];
[item setObject:currentSizing_id forKey:#"sizing_id"];
[item setObject:currentName forKey:#"name"];
[item setObject:currentSize forKey:#"size"];
[item setObject:currentType forKey:#"type"]
// here is where the magic happens
--> if (([self ifStringExists:currentType] == NO)){
[stories addObject:[item copy]];
}
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
NSLog(#"found characters in found characters: %#", string);
if ([currentElement isEqualToString:#"data_id"]) {
[currentData_id appendString:string];
} else if ([currentElement isEqualToString:#"sizing_id"]) {
[currentSizing_id appendString:string];
} else if ([currentElement isEqualToString:#"name"]) {
[currentName appendString:string];
} else if ([currentElement isEqualToString:#"size"]) {
[currentSize appendString:string];
}else if ([currentElement isEqualToString:#"type"]) {
[currentType 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 (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)dealloc {
[currentElement release];
[rssParser release];
[stories release];
[item release];
[currentData_id release];
[currentSize release];
[currentSizing_id release];
[currentName release];
[currentType release];
[super dealloc];
}
#end
my .h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "LCYDataBackedTableView.h"
#interface SizingDataViewController : LCYDataBackedTableView {
IBOutlet UITableView * newsTable;
UIActivityIndicatorView * activityIndicator;
CGSize cellSize;
NSXMLParser * rssParser;
NSMutableArray * stories;
NSMutableArray * newStories;
NSMutableArray *filteredStories;
NSString *l_uri;
NSString *myId;
NSString *idName;
BOOL *uploaded;
BOOL isFiltered;
NSIndexPath *indexPaath;
NSMutableDictionary * item;
NSString * currentElement;
NSMutableString * currentData_id, * currentSizing_id, * currentType, * currentName, * currentSize;
NSDictionary *data, *data1, *data2, *data3, *data4;
}
- (void)parseXMLFileAtURL:(NSString *)URL;
-(void)lastChance;
-(BOOL)ifStringExists:(NSString *)stringSentToCheck;
-(void)lastChance;
#end
Where you have the code [stories addObject:[item copy]]; in your parser delegate callback, don't just blindly add the new item - check if it exists already:
if (![stories containsObject:item]) {
[stories addObject:item copy];
}
Then you won't have duplicates at all.
You don't strictly need to copy item because you're creating a new one each time you start a new element. Also, if you don't define 'duplicate' as a full match to the entire dictionary then you will need to write your own contains type method which iterates the array and check the parts of each dictionary that you're interested in.
My app uses an RSS feed to populate the cells in a table view with the titles of articles from the feed. I'm trying to add the published date for each article to the corresponding cell but it isn't showing up. The titles show up just fine in as the textLabel but the date is not showing in the detailTextLabel. I have an NSLog that shows all of the pubDate items and a NSLog in didSelectRowAtIndexPath that shows the pubDate for the selected row. Any help?
RSSChannel.m
#import "RSSChannel.h"
#import "RSSItem.h"
#implementation RSSChannel
#synthesize items, title, infoString, parentParserDelegate, date;
- (id)init
{
self = [super init];
if (self)
{
// Create the container for the RSSItems this channel has
items = [[NSMutableArray alloc]init];
}
return self;
}
- (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];
[self setTitle:currentString];
}
else if ([elementName isEqual:#"pubDate"])
{
currentString = [[NSMutableString alloc]init];
[self setDate:currentString];
}
else if ([elementName isEqual:#"description"])
{
currentString = [[NSMutableString alloc]init];
[self setInfoString:currentString];
}
else if ([elementName isEqual:#"item"])
{
RSSItem *entry = [[RSSItem alloc]init];
// Set up its parent as ourselves so we can regain control of the parser
[entry setParentParserDelegate:self];
// Turn the parser to the RSSItem
[parser setDelegate:entry];
[items addObject:entry];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)str
{
[currentString appendString:str];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
currentString = nil;
if ([elementName isEqual:#"channel"])
{
[parser setDelegate:parentParserDelegate];
}
}
#end
RSSItem.m
#import "RSSItem.h"
#implementation RSSItem
#synthesize title, link, date, isActionAlert, 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 isEqualToString:#"category"]) {
NSLog(#"category");
}
if ([elementName isEqual:#"title"])
{
currentString = [[NSMutableString alloc]init];
[self setTitle:currentString];
}
else if ([elementName isEqual:#"link"])
{
currentString = [[NSMutableString alloc]init];
[self setLink:currentString];
}
else if ([elementName isEqual:#"pubDate"])
{
currentString = [[NSMutableString alloc]init];
[self setDate:currentString];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)str
{
if ([str isEqualToString:#"Action Alert"]) {
isActionAlert = YES;
}
[currentString appendString:str];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
currentString = nil;
if ([elementName isEqual:#"item"])
{
[parser setDelegate:parentParserDelegate];
}
}
#end
Table View Controller
#import "AgStoriesViewController.h"
#import "RSSChannel.h"
#import "RSSItem.h"
#import "WebViewController.h"
// #import "CustomCellBackground.h"
#import "DTCustomColoredAccessory.h"
#implementation AgStoriesViewController
{
UIActivityIndicatorView *loadingIndicator;
}
#synthesize webViewController;
- (void)viewDidLoad
{
UIImageView *background = [[UIImageView alloc]init];
background.image = [UIImage imageNamed:#"plain_app-background.png"];
CGFloat width = CGRectGetWidth(self.view.bounds);
CGFloat height = CGRectGetHeight(self.view.bounds);
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
[self.tableView setBackgroundView:background];
self.title = #"Ag News";
loadingIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
loadingIndicator.center = CGPointMake(width/2, height/2);
loadingIndicator.hidesWhenStopped = YES;
[self.view addSubview:loadingIndicator];
[loadingIndicator startAnimating];
// UIRefreshControl *refresh = [[UIRefreshControl alloc] init];
// refresh.attributedTitle = [[NSAttributedString alloc] initWithString:#"Pull to Refresh"];
// [refresh addTarget:self action:#selector(refreshView:)forControlEvents:UIControlEventValueChanged];
// self.refreshControl = refresh;
}
- (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"])
{
// If the parser saw a channel, create new instance, store in our ivar
channel = [[RSSChannel alloc]init];
// Give the channel object a pointer back to ourselves for later
[channel setParentParserDelegate:self];
// Set the parser's delegate to the channel object
[parser setDelegate:channel];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// return 0;
NSLog(#"channel items %d", [[channel items]count]);
return [[channel items]count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 50;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// return nil;
UIImageView *image = [[UIImageView alloc]init];
image.image = [UIImage imageNamed:#"CellImage.png"];
UIImageView *background = [[UIImageView alloc]init];
background.image = [UIImage imageNamed:#"plain_app-background.png"];
UIImageView *highlightedCellImage = [[UIImageView alloc]init];
highlightedCellImage.image = [UIImage imageNamed:#"HighlightedCellImage"];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell"];
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"UITableViewCell"];
cell.textLabel.font=[UIFont systemFontOfSize:16.0];
}
RSSItem *item = [[channel items]objectAtIndex:[indexPath row]];
[[cell textLabel]setText:[item title]];
[[cell detailTextLabel]setText:[item date]];
NSLog(#"Date: %#", [item date]);
tableView.backgroundColor = [UIColor clearColor];
// cell.backgroundView = [[CustomCellBackground alloc] init];
// cell.selectedBackgroundView = [[CustomCellBackground alloc] init];
cell.textLabel.backgroundColor = [UIColor clearColor];
cell.textLabel.highlightedTextColor = [UIColor blueColor];
cell.textLabel.font = [UIFont fontWithName:#"FranklinGothicStd-ExtraCond" size:20.0];
cell.textLabel.textColor = [UIColor whiteColor];
cell.detailTextLabel.backgroundColor = [UIColor clearColor];
cell.detailTextLabel.highlightedTextColor = [UIColor blueColor];
cell.detailTextLabel.font = [UIFont fontWithName:#"FranklinGothicStd-ExtraCond" size:16.0];
cell.detailTextLabel.textColor = [UIColor whiteColor];
cell.backgroundView = image;
cell.selectedBackgroundView = highlightedCellImage;
tableView.backgroundView = background;
DTCustomColoredAccessory *accessory = [DTCustomColoredAccessory accessoryWithColor:cell.textLabel.textColor];
accessory.highlightedColor = [UIColor blueColor];
cell.accessoryView =accessory;
return cell;
}
- (void)fetchEntries
{
// Create a new data container for the stuff that comes back from the service
xmlData = [[NSMutableData alloc]init];
// Construct a URL that will ask the service for what you want -
// note we can concatenate literal strings together on multiple lines in this way - this results in a single NSString instance
NSURL *url = [NSURL URLWithString:#"http://kyfbnewsroom.com/category/ag-news/feed"];
// Put that URL into an NSURLRequest
NSURLRequest *req = [NSURLRequest requestWithURL:url];
// Create a connection that will exchange this request for data from the URL
connection = [[NSURLConnection alloc]initWithRequest:req delegate:self startImmediately:YES];
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self)
{
[self fetchEntries];
}
return self;
}
// This method will be called several times as the data arrives
- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
// 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
{
/* We are just checking to make sure we are getting the XML
NSString *xmlCheck = [[NSString alloc]initWithData:xmlData encoding:NSUTF8StringEncoding];
NSLog(#"xmlCheck = %#", xmlCheck);*/
[loadingIndicator stopAnimating];
// Create the parser object with the data received from the web service
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:xmlData];
// Give it a delegate
[parser setDelegate:self];
//Tell it to start parsing - the document will be parsed and the delegate of NSXMLParser will get all of its delegate messages sent to it before this line finishes execution - it is blocking
[parser parse];
// Get rid of the XML data as we no longer need it
xmlData = nil;
// Reload the table.. for now, the table will be empty
[[self tableView]reloadData];
NSLog(#"%#\n %#\n %#\n", channel, [channel title], [channel infoString]);
}
- (void)connection:(NSURLConnection *)conn didFailWithError:(NSError *)error
{
// Release the connection object, we're done with it
connection = nil;
// Release the xmlData object, we're done with it
xmlData = nil;
// Grab the description of the error object passed to us
NSString *errorString = [NSString stringWithFormat:#"Fetch failed: %#", [error localizedDescription]];
// Create and show an alert view with this error displayed
UIAlertView *av = [[UIAlertView alloc]initWithTitle:#"Error" message:errorString delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[av show];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Push the web view controller onto the navigation stack - this implicitly creates the web view controller's view the first time through
// [[self navigationController]pushViewController:webViewController animated:YES];
[self.navigationController pushViewController:webViewController animated:NO];
// Grab the selected item
RSSItem *entry = [[channel items]objectAtIndex:[indexPath row]];
NSLog(#"Channel Items: %#", [[channel items]objectAtIndex:[indexPath row]]);
// Construct a URL with the link string of the item
NSURL *url = [NSURL URLWithString:[entry link]];
NSLog(#"Link: %#", [entry link]);
// Construct a request object with that URL
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSLog(#"URL: %#", url);
// Load the request into the web view
[[webViewController webView]loadRequest:req];
webViewController.hackyURL = url;
NSLog(#"Request: %#", req);
// Set the title of the web view controller's navigation item
// [[webViewController navigationItem]setTitle:[entry title]];
NSLog(#"Title: %#", [entry title]);
NSLog(#"Pub Date: %#", [entry date]);
}
#end
You're using UITableViewCellStyleDefault when constructing your cell. This style does not provide the detailTextLabel. You should probably take UITableViewCellStyleSubtitle.
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
I'm trying to debug a crash I'm experiencing...
I'm getting some data from a web server, so I've set up three classes:
Child
ChildConnection
ChildParser
ChildConnection contacts the web service and gets the data and starts the ChildParser, which then parse the xml and saves it as a Child object...
I've got it working in a project, where instead of having the ChildConnection, I set up the connection in the AppDelegate, and the issue I'm having in my current project is to do with delegates(at least that's what I think)... since I'm getting the error:
-[AppDelegate children]: unrecognized selector sent to instance 0x6b07e80
I'm fairly certain that the error is caused by: (NOTE: I'm pretty new to this)
- (ChildParser *) initChildParser {
self = [super init];
if(self)
{
childConnection = (ChildConnection *)[[UIApplication sharedApplication] delegate];
NSLog(#"Init");
}
return self;
}
ChildConnection.h:
#interface ChildConnection : NSObject
{
NSMutableArray *children;
NSMutableData *webData;
}
#property (nonatomic, retain) NSMutableArray *children;
-(void)connectionSetUp;
#end
ChildConnection.m:
#import "ChildConnection.h"
#import "ChildParser.h"
#implementation ChildConnection
#synthesize children;
- (void)connectionSetUp
{
NSString *soapMsg =
[NSString stringWithFormat:
Soap message left out due to sensitive data
];
NSURL *url = [NSURL URLWithString:#"Private"];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
// Calculate the length of the post
NSString *postLength = [NSString stringWithFormat:#"%d", [soapMsg length]];
// Set the headers
[req addValue:postLength forHTTPHeaderField:#"Content-Length"];
[req addValue:#"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[req addValue:#"PRIVATE" forHTTPHeaderField:#"SOAPAction"];
// Set the HTTP method and body
[req setHTTPMethod:#"POST"];
[req setHTTPBody:[soapMsg dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *myConnection = [[NSURLConnection alloc] initWithRequest:req delegate:self];
if(myConnection)
{
NSLog(#"Connection established");
webData = [NSMutableData data];
} else
{
NSLog(#"Connection failed");
}
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"didReceiveResponse");
[webData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//NSLog(#"didReceiveData");
[webData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", [error localizedDescription]);
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Finished loading");
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:webData];
//Initialize the delegate.
ChildParser *parser = [[ChildParser 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!!!");
*/
//NSLog(#"Count: %#", [ count]);
}
#end
ChildParser.h:
#class Child;
#class ChildConnection;
#interface ChildParser : NSObject <NSXMLParserDelegate>
{
NSMutableString *currentElementValue;
Child *aChild;
ChildConnection *childConnection;
}
- (ChildParser *) initChildParser;
#end
.m:
#import "ChildParser.h"
#import "Child.h"
#import "ChildConnection.h"
#implementation ChildParser
- (ChildParser *) initChildParser {
self = [super init];
if(self)
{
childConnection = (ChildConnection *)[[UIApplication sharedApplication] delegate];
NSLog(#"Init");
}
return self;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict
{
NSLog(#"didstart");
if([elementName isEqualToString:#"GetKidsResult"])
{
// initialize the array
if(!childConnection.children)
{
childConnection.children = [[NSMutableArray alloc] init];
}
}
else if([elementName isEqualToString:#"a:KeyValueOfintKidf4KEWLbb"])
{
if(!aChild)
{
//Initialize the child.
aChild = [[Child alloc] init];
}
}
//NSLog(#"Processing Element: %#", elementName);
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
NSLog(#"foundcharacters");
/*
if(!currentElementValue)
{
currentElementValue = [[NSMutableString alloc] initWithString:string];
}
else
{
[currentElementValue appendString:string];
}*/
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
//NSLog(#"El name: %#", elementName);
if([elementName isEqualToString:#"GetKidsResult"])
{
NSLog(#"end of xml");
return;
}
if([elementName isEqualToString:#"a:KeyValueOfintKidf4KEWLbb"])
{
//NSLog(#"Found end of child");
//[childConnection.children addObject:aChild];
//NSLog(#"added");
//int i = [childConnection.children count];
//NSLog(#"Count: %d", i);
//aChild = nil;
}
else if([elementName isEqualToString:#"a:Key"])
{
//NSLog(#"Found key: %#", currentElementValue);
//aChild.key = [currentElementValue intValue];
//NSLog(#"key: %#", aChild.key);
}
else if([elementName isEqualToString:#"b:CPR"])
{
//NSLog(#"Found cpr");
//aChild.cpr = [currentElementValue intValue];
}
else if([elementName isEqualToString:#"b:CheckedIn"])
{
//NSLog(#"Found checkedIn");
//aChild.checkedIn = [currentElementValue boolValue];
}
else if([elementName isEqualToString:#"b:FirstName"])
{
//NSLog(#"Found firstname: %#", currentElementValue);
//[aChild setValue:currentElementValue forKey:#"firstName"];
//aChild.firstName = currentElementValue;
}
else if([elementName isEqualToString:#"b:Gender"])
{
//NSLog(#"found gender");
//aChild.gender = currentElementValue;
}
else if([elementName isEqualToString:#"b:Id"])
{
//NSLog(#"found id");
aChild.idChild = [currentElementValue intValue];
}
else if([elementName isEqualToString:#"b:IsOnTour"])
{
//NSLog(#"found isontour");
//aChild.isOnTour = [currentElementValue boolValue];
}
else if([elementName isEqualToString:#"b:LastName"])
{
//NSLog(#"found lastname: %#", currentElementValue);
//aChild.lastName = currentElementValue;
}
else if([elementName isEqualToString:#"b:GroupName"])
{
//NSLog(#"found groupname");
//aChild.groupName = currentElementValue;
}
currentElementValue = nil;
}
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
NSLog(#"didEndDocument");
//NSLog(#"Number of objects: %d", [childConnection.children count]);
[[NSNotificationCenter defaultCenter] postNotificationName:#"finishedParsing" object:nil];
}
#end
UPDATE
Okay, so got a bit further... I'm now getting a SIGABRT in the class where I use the data:
#import "AllView.h"
#import "CustomCellNoSubtitle.h"
#import "DTCustomColoredAccessory.h"
#import "Child.h"
#import "ChildConnection.h"
#implementation AllView
#synthesize allChildrenTable, childView, whichGroupLabel, charIndex;
-(void)receivedData
{
NSLog(#"data update gotten");
charIndex = [[NSMutableArray alloc] init];
listOfNames = [[NSMutableArray alloc] init];
for(int i=0; i<[childConnection.children count]-1; i++)
{
// get the person
Child *aChild = [childConnection.children objectAtIndex:i];
// get both first and last name and join them
NSString *joinName = [NSString stringWithFormat:#"%# %#", aChild.firstName, aChild.lastName];
// save the full name to an array of all the names
[listOfNames addObject:joinName];
// get the first letter of the first name
NSString *firstLetter = [aChild.firstName substringToIndex:1];
NSLog(#"first letter: %#", firstLetter);
// if the index doesn't contain the letter
if(![charIndex containsObject:firstLetter])
{
// then add it to the index
NSLog(#"adding: %#", firstLetter);
[charIndex addObject:firstLetter];
}
}
[allChildrenTable reloadData];
}
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Deselect the row, so it's clear when the user returns
[allChildrenTable deselectRowAtIndexPath:indexPath animated:YES];
if(self.childView == nil)
{
ChildView *cView = [[ChildView alloc] initWithNibName:#"ChildView" bundle:[NSBundle mainBundle]];
self.childView = cView;
}
[self.navigationController pushViewController:childView animated:YES];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// set the number of sections in the table to match the number of first letters
return [charIndex count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
// set the section title to the matching letter
return [charIndex objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// get the letter in each section
NSString *alphabet = [charIndex objectAtIndex:section];
// get the names beginning with the letter
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", alphabet];
NSArray *names = [listOfNames filteredArrayUsingPredicate:predicate];
return [names count];
}
// set up an index
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return charIndex;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
CustomCellNoSubtitle *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
//cell = [[CustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier];
//cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
cell = [[CustomCellNoSubtitle alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
//cell.frame = CGRectZero;
}
/*
//---get the letter in the current section---
NSString *alphabet = [charIndex objectAtIndex:[indexPath section]];
//---get all states beginning with the letter---
NSPredicate *predicate =
[NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", alphabet];
NSArray *names = [listOfNames filteredArrayUsingPredicate:predicate];
if ([names count]>0) {
//---extract the relevant state from the states object---
NSString *cellValue = [names objectAtIndex:indexPath.row];
cell.primaryLabel.text = cellValue;
}
cell.myImageView.image = [UIImage imageNamed:#"kidblank.png"];*/
return cell;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//childConnection = (ChildConnection *)[[UIApplication sharedApplication] delegate];
childConnection =[[ChildConnection alloc] init];
[allChildrenTable reloadData];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Set up a connection to the server to fetch the list of children
ChildConnection *childConnection = [[ChildConnection alloc] init];
[childConnection connectionSetUp];
// Set up a listener to receive notice when the parser is done
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receivedData) name:#"finishedParsing" object:nil];
}
The problem looks pretty simple.
In your very first pasted function, you are assigning your app delegate to the variable childConnection.
childConnection = (ChildConnection *)[[UIApplication sharedApplication] delegate];
Surely you actually want to assign a new instance of the ChildConnection class to that property instead. Like this:
childConnection = [[ChildConnection alloc] init];
I know that Objective-C errors can sometimes be hard to make sense of, but the one you are getting is actually pretty clear:
[AppDelegate children]: unrecognised selector
So it's complaining that you are calling a method/property "children" on the app delegate. But why would you be calling anything on the app delegate if you aren't using it any more? And why would you call a method called "children" on it, when that's actually defined as a property of the ChildConnection class, not the app delegate?
Answer: because an object you thought was a ChildConnection is actually the app delegate.
UPDATE: It looks like you need to use the ChildConnection in more than one place. The easiest way to do this is to make a shared instance. Add this method to your ChildConnection class:
+ (ChildConnection *)sharedConnection
{
static ChildConnection *sharedConnection = nil;
if (sharedConnection == nil)
{
sharedConnection = [[self alloc] init];
}
return sharedConnection;
}
Now in your other classes, wherever you've used [[ChildConnection alloc] init] use [ChildConnection sharedInstance] instead.
Your right the offending piece of code is :
if(self)
{
childConnection = (ChildConnection *)[[UIApplication sharedApplication] delegate];
NSLog(#"Init");
}
And the reason why is your casting your AppDelegate to a ChildConnection Object, you can't do this because well it isn't a ChildConnection.
If you want to reference your childConnection in your AppDelegate i recommend the following:
+ (AppDelegate*)sharedDelegate;
//Implementation
+ (AppDelegate*)sharedDelegate {
return (AppDelegate*)[[UIApplication sharedApplication] delegate];
}
So this way you reference your childConnection like so:
[AppDelegate sharedDelegate].childConnection;
If you need data the moment the App starts initialise the childConnection in:
application:didFinishLaunchingWithOptions: