I have a simple RSS reader. Stories are downloaded, put into a UITableView, and when you click it, each story loads in a UIWebView. It works great. Now though, I'd like to incorporate an image on the left side (like you'd see in the YouTube app). However, since my app pulls from an RSS feed, I can't simply specify image X to appear in row X because row X will be row Y tomorrow, and things will get out of order, you know? I am currently pulling from a YouTube RSS feed, and can get the video title, description, publication date, but I'm stuck as to how to pull the little thumbnail besides each entry in the feed.
As you can probably tell, I'm a coding newbie (this being my first application other than a Hello World app) and I'm getting so frustrated by my own lack of knowledge.
Thanks!
BTW, here's some sample code:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
//NSLog(#"found this element: %#", elementName);
if (currentElement) {
[currentElement release];
currentElement = nil;
}
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];
}
}
I would recommend trying out TouchXML for xml parsing. I find it a lot easier to work with.
Fetch the url for the image like you fetch any other text field. Then when you create the object and add it to the story do something like:
currentImage = [UIImage imageWithData:[NSData dataWithContentsOfURL: [NSURL URLWithString: theUrl]]]
Hope this helps
Have the same problem,but solved with references from Youtube API,
consider this as u r youtube feed,
http://gdata.youtube.com/feeds/base/users/[insert UserName]/uploads
where u will get a xml with media:thumbnail tag which u can used to display thumbnail images of youtube.
Hope it will help u !!!
I would use NSScanner to scan your url from the feed item and get the youtube video id. Then I would then use the video ID to get the thumbnail image from a URL. You can pick which thumbnail URL you want from this answer here:https://stackoverflow.com/a/2068371/1484168
Related
At the moment i've got the following code to get data from an xml file. This works so far
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict{
currentElement = [elementName copy];
if ([elementName isEqualToString:#"Placemark"]) {
placemarkData = [[NSMutableDictionary alloc] init];
currentTitle = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([currentElement isEqualToString:#"name"])
[placemarkData addObject:string forKey:currentElement];
if ([currentElement isEqualToString:#"address"])
[placemarkData addObject:string forKey:currentElement];
if ([currentElement isEqualToString:#"coordinates"])
[placemarkData addObject:string forKey:currentElement];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"Placemark"]) {
[Placemarks addObject:[placemarkData copy]];
NSString *batsen = [placemarkData objectForKey:#"name"];
NSLog(#"adding story: %#", batsen);
}
}
This dictionary will be loaded into a array. Problem is that where this array got loaded in need to find the right entry in the array. I do it like this
TabbedCalculationAppDelegate *appDelegate = (TabbedCalculationAppDelegate *)[[UIApplication sharedApplication] delegate];
NSArray *jean = appDelegate.Placemarks;
NSDictionary *boekje = [jean objectAtIndex:1];
NSString *coordinaten = [boekje objectForKey:#"coordinates"];
NSString *naam = [boekje objectForKey:#"name"];
NSLog(#"poep: %#" , naam);
NSLog(#"wwhoppa: %#", coordinaten);
titel.text = coordinaten;
But since arrays works with index I can't find a way to get the right entry. To clarify, a user clicks in a mapview on an annotation. This annotation then gets the corresponding detailview. The detailview can check which annotation is clicked by the view.annotation.title;
So I actually need a dictionary in a dictionary with name as key in the root dictionary. Is this possible? and on what way I can implement this?
Is this a little bit clear? Else just ask!
Thnx guys
Yes, this is a good idea. Just pass the 'inner' dictionary as the object parameter to setObject:forKey: on the 'outer' dictionary. It'll just work. For example:
NSMutableDictionary *outer=[[NSMutableDictionary alloc] init];
NSDictionary *inner=[NSDictionary dictionaryWithObject:#"hello" forKey:#"world"];
[outer setObject:inner forKey:#"greetings"];
I've been very unfortunate with my programming. I am still rather new to Objective-C, but I am trying to learn as quickly as possible.
I need to complete an RSS Reader for iPhones application, a relatively simple one which parses the rss feed, displays it in a navigation-table view and when you click on an article you are taken to a main page.
Unfortunately, I am having difficulty with the parsing aspect. Currently, the program downloads all the articles, but I would like to display it in lists of 10, along with a next button at the bottom. Once the next button is clicked, the parsing continues and the next 10 are on display.
I am sorry but I cannot show you the code I am using at the moment as I am on my home computer and the project is on the office mac. If anyone could give me some Ideas i would be most grateful. I have tried a number of methods (making an additional array to act as an article counter so I could record which article is which for which list, for example) but i keep running into roadblocks as I just dont know how to use the program well enough to do that.
Please, I am in a lot of need! Thank you.
(This is me again)
I am sorry if this is rather vague, but I believe I can give sample code. I am trying to make it that the program pauses parsing after 10 articles are parsed, displays those 10, then continues parsing and displaying another 10 if a next button is pressed.
In the parser.m, i have written:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
currentElement = [elementName copy];
if ([elementName isEqualToString:#"item"]) {
item = [[NSMutableDictionary alloc] init];
self.currentTitle = [[NSMutableString alloc] init];
self.currentDate = [[NSMutableString alloc] init];
self.currentSummary = [[NSMutableString alloc] init];
self.currentLink = [[NSMutableString alloc] init];
self.currentImage = [[NSMutableString alloc] init];
}//IF END
//podcast url is an attribute of the element enclosure
if ([currentElement isEqualToString:#"enclosure"]) {
[currentImage appendString:[attributeDict objectForKey:#"url"]];
NSLog(#"Image = %#", currentImage);
}//IF END
else if([currentElement isEqualToString:#"img"]){
[currentImage appendString:[attributeDict objectForKey:#"src"]];
NSLog(#"Image = %#", currentImage);
}//ELSE IF END
}
I also have the didEndElement and Found characters section:
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"item"]) {
[item setObject:self.currentTitle forKey:#"title"];
[item setObject:self.currentLink forKey:#"link"];
[item setObject:self.currentSummary forKey:#"summary"];
[item setObject:self.currentImage forKey:#"image"];
// Parse date here
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
[dateFormatter setDateFormat:#"EEE, d MMM yyyy"]; // Thu, 18 Jun 2010 04:48:09 -0700
NSLog(#"FC date1 = %#", self.currentDate);
NSDate *date = [[NSDate alloc] init];
date = [dateFormatter dateFromString:currentDate];
NSLog(#"FC date2 = %#", date);
[item setObject:self.currentDate forKey:#"date"];
//[item setObject:date forKey:#"date"];
[date release];
[items addObject:[item copy]];
NSLog(#"Item details = %#", items);
[count addObject:[item objectForKey:#"title"]];
NSLog(#"count = %#", count);
}//IF END
}
I have also been having some issues with formatting the date, but thats a minor issue.
also:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([currentElement isEqualToString:#"title"]) {
[self.currentTitle appendString:string];
} else if ([currentElement isEqualToString:#"link"]) {
[self.currentLink appendString:string];
} else if ([currentElement isEqualToString:#"image"]) {
[self.currentImage appendString:string];
} else if ([currentElement isEqualToString:#"description"]) {
[self.currentSummary appendString:string];
} else if ([currentElement isEqualToString:#"pubDate"]) {
[self.currentDate appendString:string];
NSCharacterSet* charsToTrim = [NSCharacterSet characterSetWithCharactersInString:#" \n"];
[self.currentDate setString: [self.currentDate stringByTrimmingCharactersInSet: charsToTrim]];
}//IF-ELSE-IF END
}
I would be most grateful if someone could give me a tip on what to do to pause the program...or allow me to parse in groups of 10...I am at a loss ;_;
Thank you for your time.
I've parsed an xml and stored the parsed data on strings which are property declared, retained and synthesized, the values are getting into these strings during parsing, but are being invalidated after the parser finish parsing. I'm not able to access them from another IBAction method, where i get EXEC BAD ACCESS error, which, from my experiences, think that arises when the debugger is accessing an invalidated memory.
- (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:#"resp"]) {
// clear out our story item caches...
}
else if ([currentElement isEqualToString:#"org"]) {
name = [attributeDict objectForKey:#"fileid"];
extention = [attributeDict objectForKey:#"extension"];
NSLog(#"image named %# of type %#",name,extention);
}
else if ([currentElement isEqualToString:#"photo"]) {
photoid = [attributeDict objectForKey:#"photoid"];
NSLog (#"photo id = %#",photoid);
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
//NSLog(#"found characters: %#", string);
// save the characters for the current item...
if ([currentElement isEqualToString:#"userid"]) {
userid =[NSString stringWithString:string];
NSLog (#"user id = %#",userid);
}
else if ([currentElement isEqualToString:#"albumid"]) {
albumid =[NSString stringWithString:string];
NSLog (#"album id = %#",albumid);
}
}
This portion is working fine, but
- (IBAction)download {
NSString *urlstr = [NSString stringWithFormat:#"http://staging-data.mysite.com/%#/albumphoto/%#/%#/%#.%#",userid,albumid,photoid,name,extention];
NSLog(urlstr);
NSURL *url= [NSURL URLWithString:urlstr];
NSData *imgdata = [[NSData alloc]initWithContentsOfURL:url];
UIImage *img = [UIImage imageWithData:imgdata];
newImage.image=img;
[imgdata release];
}
This results in error. pls help
I suggest you look carefully at this line:
name = [attributeDict objectForKey:#"fileid"];
Which sets an attribute to an NSString owned by the XML parser without copying it, retaining it etc. I suggest you take a copy, and retain that.
My concern is that when the XML parser goes away, it takes the name string with it, along with extension and photoid.
You have to implement this method also to know when an end tag is encountered.
(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
I have made a simple rss reader. The app loads an xml atom file in an array.
Now I have added categories to my atom feed, which are first loaded in the array
What is the best way to add drill down functionality programmatically.
Now only the categories are loaded into the array and displayed.
This is the implementation code
.....
loading xml file <snip>
.....
- (void)parserDidStartDocument:(NSXMLParser *)parser {
NSLog(#"found file and started parsing");
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
NSString * errorString = [NSString stringWithFormat:#"Unable to download story feed from web site (Error code %i )", [parseError code]];
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:#"entry"]) {
// clear out our story item caches...
Categoryentry = [[NSMutableDictionary alloc] init];
currentID = [[NSMutableString alloc] init];
currentTitle = [[NSMutableString alloc] init];
currentSummary = [[NSMutableString alloc] init];
currentContent = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
//NSLog(#"ended element: %#", elementName);
if ([elementName isEqualToString:#"entry"]) {
// save values to an entry, then store that item into the array...
[Categoryentry setObject:currentTitle forKey:#"title"];
[Categoryentry setObject:currentID forKey:#"id"];
[Categoryentry setObject:currentSummary forKey:#"summary"];
[Categoryentry setObject:currentContent forKey:#"content"];
[categories addObject:[Categoryentry copy]];
NSLog(#"adding category: %#", 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:#"id"]) {
[currentID appendString:string];
} else if ([currentElement isEqualToString:#"summary"]) {
[currentSummary appendString:string];
} else if ([currentElement isEqualToString:#"content"]) {
[currentContent appendString:string];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
[activityIndicator stopAnimating];
[activityIndicator removeFromSuperview];
NSLog(#"all done!");
NSLog(#"categories array has %d entries", [categories count]);
[newsTable reloadData];
}
Apple provides a good sample app for demonstrating a drill-down tableview:
SimpleDrillDown
Write a generic UITableViewController subclass that takes an array of values. Then, when the user taps on a row, get the array of posts associated with the selected category and pass that to a new view controller. Then, push the view controller onto the stack, using [[self navigationController] pushViewController:nextViewController animated:YES];.
I've just released an open source RSS/Atom Parser for iPhone and hopefully it might be of some use.
I'd love to hear your thoughts on it too!
I'm parsing an RSS feed with NSXMLParser and it's working fine for the title and other strings but one of the elements is an image thats like
<!CDATA <a href="http:image..etc>
How do I add that as my cell image in my table view? Would I define that as an image type?
This is what i'm using to do my parsing:
- (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:#"description"];
[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];
}
}
You can use
- (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
{
NSString *someString = [[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
}
The point of CDATA is that anything within it is not treated as part of the XML document.
So if you have tags in CDATA the parser will ignore them.
I'm guessing this CDATA is in the description element. So you'll need to extract the tags from the "description" element, either manually or via another instance of a parser.