解析 XML 文件中的链接并将其推送到 UIWebView [英] Parsing links from XML file and pushing it to a UIWebView

查看:56
本文介绍了解析 XML 文件中的链接并将其推送到 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

NSMutableDictionaryNSMutableStrring 添加到您的解析器标头:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆