解析 XML 文件中的链接并将其推送到 UIWebView [英] Parsing links from XML file and pushing it to a UIWebView
问题描述
我一直在尝试解析 XML 文件,以便使用后台提取从网站获取文章.
I have been trying to parse an XML file in order to get articles from a website using background fetch.
教程的链接是此处.
我已经成功完成了教程并解析了我的 XML 文件,但是当用户点击文章时,我希望他们在 UIWebView 中看到它,而不是通过 safari 将链接推送到外部.
I've successfully completed the tutorial and parsed my XML file, but instead of pushing the link externally through safari, when the user clicks on the article I would like them to see it in a UIWebView.
我将如何在我的代码中实现这一点?
How would I implement this in my code?
我的代码:
NewsViewController.h(此文件加载一个运行后台获取以获取文章的 uitableview):
#import <UIKit/UIKit.h>
@interface NewsViewController : UIViewController<UITableViewDelegate, UITableViewDataSource>
@property (weak, nonatomic) IBOutlet UITableView *tblNews;
- (IBAction)removeDataFile:(id)sender;
-(void)fetchNewDataWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
@end
NewsViewController.m:
#import "NewsViewController.h"
#define NewsFeed @"http://www.teamfortress.com/rss.xml"
#import "XMLParser.h"
@interface NewsViewController ()
@property (nonatomic, strong) UIRefreshControl *refreshControl;
@property (nonatomic, strong) NSArray *arrNewsData;
@property (nonatomic, strong) NSString *dataFilePath;
-(void)refreshData;
-(void)performNewFetchedDataActionsWithDataArray:(NSArray *)dataArray;
@end
@implementation NewsViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// 1. Make self the delegate and datasource of the table view.
[self.tblNews setDelegate:self];
[self.tblNews setDataSource:self];
// 2. Specify the data storage file path.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDirectory = [paths objectAtIndex:0];
self.dataFilePath = [docDirectory stringByAppendingPathComponent:@"newsdata"];
// 3. Initialize the refresh control.
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self
action:@selector(refreshData)
forControlEvents:UIControlEventValueChanged];
[self.tblNews addSubview:self.refreshControl];
// 4. Load any saved data.
if ([[NSFileManager defaultManager] fileExistsAtPath:self.dataFilePath]) {
self.arrNewsData = [[NSMutableArray alloc] initWithContentsOfFile:self.dataFilePath];
[self.tblNews reloadData];
}
}
- (IBAction)removeDataFile:(id)sender {
if ([[NSFileManager defaultManager] fileExistsAtPath:self.dataFilePath]) {
[[NSFileManager defaultManager] removeItemAtPath:self.dataFilePath error:nil];
self.arrNewsData = nil;
[self.tblNews reloadData];
}
}
-(void)refreshData{
XMLParser *xmlParser = [[XMLParser alloc] initWithXMLURLString:NewsFeed];
[xmlParser startParsingWithCompletionHandler:^(BOOL success, NSArray *dataArray, NSError *error) {
if (success) {
[self performNewFetchedDataActionsWithDataArray:dataArray];
[self.refreshControl endRefreshing];
}
else{
NSLog(@"%@", [error localizedDescription]);
}
}];
}
-(void)performNewFetchedDataActionsWithDataArray:(NSArray *)dataArray{
// 1. Initialize the arrNewsData array with the parsed data array.
if (self.arrNewsData != nil) {
self.arrNewsData = nil;
}
self.arrNewsData = [[NSArray alloc] initWithArray:dataArray];
// 2. Reload the table view.
[self.tblNews reloadData];
// 3. Save the data permanently to file.
if (![self.arrNewsData writeToFile:self.dataFilePath atomically:YES]) {
NSLog(@"Couldn't save data.");
}
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.arrNewsData.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"idCellNewsTitle"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"idCellNewsTitle"];
}
NSDictionary *dict = [self.arrNewsData objectAtIndex:indexPath.row];
cell.textLabel.text = [dict objectForKey:@"title"];
cell.detailTextLabel.text = [dict objectForKey:@"pubDate"];
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 80.0;
}
//THIS IS THE SECTION OF CODE THAT OPENS THE LINKS
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSDictionary *dict = [self.arrNewsData objectAtIndex:indexPath.row];
NSString *newsLink = [dict objectForKey:@"link"];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:newsLink]];
}
//END OF THE SECTION
-(void)fetchNewDataWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
XMLParser *xmlParser = [[XMLParser alloc] initWithXMLURLString:NewsFeed];
[xmlParser startParsingWithCompletionHandler:^(BOOL success, NSArray *dataArray, NSError *error) {
if (success) {
NSDictionary *latestDataDict = [dataArray objectAtIndex:0];
NSString *latestTitle = [latestDataDict objectForKey:@"title"];
NSDictionary *existingDataDict = [self.arrNewsData objectAtIndex:0];
NSString *existingTitle = [existingDataDict objectForKey:@"title"];
if ([latestTitle isEqualToString:existingTitle]) {
completionHandler(UIBackgroundFetchResultNoData);
NSLog(@"No new data found.");
}
else{
[self performNewFetchedDataActionsWithDataArray:dataArray];
completionHandler(UIBackgroundFetchResultNewData);
NSLog(@"New data was fetched.");
}
}
else{
completionHandler(UIBackgroundFetchResultFailed);
NSLog(@"Failed to fetch new data.");
}
}];
}
@end
XMLParser.h(此文件解析 XML 以获取标题、发布日期、链接等)
#import <Foundation/Foundation.h>
@interface XMLParser : NSObject <NSXMLParserDelegate>
-(id)initWithXMLURLString:(NSString *)xmlUrlString;
-(void)startParsingWithCompletionHandler:(void(^)(BOOL success, NSArray *dataArray, NSError *error))completionHandler;
@end
XMLParser.m:
#import "XMLParser.h"
@interface XMLParser()
@property (nonatomic, strong) NSXMLParser *xmlParser;
@property (nonatomic, strong) NSOperationQueue *operationQueue;
@property (nonatomic, strong) NSMutableArray *arrParsedData;
@property (nonatomic, strong) NSString *currentElement;
@property (nonatomic, strong) NSString *newsTitle;
@property (nonatomic, strong) NSString *newsPubDate;
@property (nonatomic, strong) NSString *newsLink;
@property (nonatomic, strong) void (^completionHandler)(BOOL, NSArray *, NSError *);
@property (nonatomic) BOOL isNewsItem;
@property (nonatomic) BOOL allowedData;
-(void)parse;
-(void)endParsingWithError:(NSError *)error;
@end
@implementation XMLParser
-(id)initWithXMLURLString:(NSString *)xmlUrlString{
self = [super init];
if (self) {
self.xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:xmlUrlString]];
self.xmlParser.delegate = self;
self.operationQueue = [NSOperationQueue new];
self.currentElement = @"";
self.isNewsItem = NO;
self.allowedData = NO;
}
return self;
}
#pragma mark - Public method implementation
-(void)startParsingWithCompletionHandler:(void (^)(BOOL, NSArray *, NSError *))completionHandler{
self.completionHandler = completionHandler;
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(parse)
object:nil];
[self.operationQueue addOperation:operation];
}
#pragma mark - Private method implementation
-(void)parse{
if (self.xmlParser != nil) {
[self.xmlParser parse];
}
}
-(void)endParsingWithError:(NSError *)error{
BOOL success = (error == nil) ? YES : NO;
self.completionHandler(success, self.arrParsedData, error);
}
#pragma mark - NSXMLParserDelegate method implementation
-(void)parserDidStartDocument:(NSXMLParser *)parser{
if (self.arrParsedData != nil) {
[self.arrParsedData removeAllObjects];
self.arrParsedData = nil;
}
self.arrParsedData = [[NSMutableArray alloc] init];
}
-(void)parserDidEndDocument:(NSXMLParser *)parser{
[self performSelectorOnMainThread:@selector(endParsingWithError:) withObject:nil waitUntilDone:NO];
}
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
if ([elementName isEqualToString:@"item"]) {
self.isNewsItem = YES;
}
if (self.isNewsItem) {
if ([elementName isEqualToString:@"title"] ||
[elementName isEqualToString:@"pubDate"] ||
[elementName isEqualToString:@"link"]) {
self.allowedData = YES;
}
}
self.currentElement = elementName;
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:@"item"]) {
self.isNewsItem = NO;
NSDictionary *dict = @{@"title": self.newsTitle,
@"pubDate": self.newsPubDate,
@"link": self.newsLink
};
[self.arrParsedData addObject:dict];
}
if (self.isNewsItem) {
if ([elementName isEqualToString:@"title"] ||
[elementName isEqualToString:@"pubDate"] ||
[elementName isEqualToString:@"link"]) {
self.allowedData = NO;
}
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if (self.allowedData) {
if ([self.currentElement isEqualToString:@"title"]) {
self.newsTitle = string;
}
else if ([self.currentElement isEqualToString:@"pubDate"]){
self.newsPubDate = string;
}
else if ([self.currentElement isEqualToString:@"link"]){
self.newsLink = string;
}
}
}
-(void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{
[self performSelectorOnMainThread:@selector(endParsingWithError:) withObject:parseError waitUntilDone:NO];
}
-(void)parser:(NSXMLParser *)parser validationErrorOccurred:(NSError *)validationError{
[self performSelectorOnMainThread:@selector(endParsingWithError:) withObject:validationError waitUntilDone:NO];
}
@end
如果您想自己运行该项目,可以在 Github 此处
If you would like to run the project yourself, you can find it on Github here
注意 使用链接时,Xcode 项目位于Your Guide to TF2"下.
NOTE When using the link, the Xcode project is under "Your Guide to TF2".
感谢任何提供帮助的人!
Thanks to anyone that helps!
推荐答案
添加一个 UIViewController
,包括一个 UIWebView
.更改您的 didSelectRowAtIndexPath
Add a UIViewController
, include a UIWebView
. Change your didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:@"detail"]){
DetailViewController *detail = segue.destinationViewController;
NSIndexPath *indexPath = [self.tblNews indexPathForSelectedRow];
detail.item = [self.arrNewsData objectAtIndex:indexPath.row];
}
}
在您的 Detailview 头文件中:
In your Detailview header file:
#import <UIKit/UIKit.h>
@interface DetailViewController : UIViewController<UIWebViewDelegate> {
NSDictionary *item;
}
@property (retain, nonatomic) NSDictionary *item;
@property (retain, nonatomic) IBOutlet UIWebView *itemSummary;
@end
在您的实施中:
#import "DetailViewController.h"
@interface DetailViewController ()
@end
@implementation DetailViewController
@synthesize item;
@synthesize itemSummary = _itemSummary;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_itemSummary.delegate = self;
_itemSummary.scalesPageToFit = YES;
NSURL* url = [NSURL URLWithString:[item objectForKey:@"link"]];
[_itemSummary loadRequest:[NSURLRequest requestWithURL:url]];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
将 NSMutableDictionary
和 NSMutableStrring
添加到您的解析器标头:
Add an NSMutableDictionary
and NSMutableStrring
to your parser header:
@interface XMLParser : NSObject <NSXMLParserDelegate> {
NSMutableDictionary *item;
NSMutableString * currentLink;
}
@property (retain, nonatomic) NSMutableString *currentLink;
在您的实施中:
在你的 didStartElement 中:
Within your didStartElement:
if ([elementName isEqualToString:@"item"]) {
item = [[NSMutableDictionary alloc] init];
self.currentLink = [[NSMutableString alloc] init];
self.isNewsItem = YES;
}
在你的 didEndElement 中:
in your didEndElement:
if ([elementName isEqualToString:@"item"]) {
self.isNewsItem = NO;
[item setObject:self.currentLink forKey:@"link"];
在您找到的字符中:
else if ([self.currentElement isEqualToString:@"link"]){
self.newsLink = string;
[self.currentLink appendString:string];
}
在你的故事板中:将您的 tableviewcontroller 嵌入到导航控制器中,从您的 tableview 添加一个 push segue 到详细视图,添加detail"的标识符.
In your storyboard: Embed your tableviewcontroller in a nav controller, add a push segue from your tableview to the detail view, add the identifier of "detail".
还将更改提交到您的 git.
Also committed the changes to your git.
这篇关于解析 XML 文件中的链接并将其推送到 UIWebView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!