2014-04-06 57 views
0

我一直试图解析XML文件,以便从使用后台获取的网站获取文章。从XML文件解析链接并将其推送到UIWebView

指南的链接是here

我已经成功完成了本教程并解析了我的XML文件,但不是通过Safari浏览器从外部推送链接,当用户单击文章时,我希望他们在UIWebView中看到它。

我该如何在我的代码中实现?

我的代码:

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 here

注意当使用该链接时,Xcode项目在“您的TF2指南”下。

感谢任何人的帮助!

回答

1

添加一个UIViewController,包括一个UIWebView。更改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头文件:

#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到您的解析器头:

@interface XMLParser : NSObject <NSXMLParserDelegate> { 
    NSMutableDictionary *item; 
    NSMutableString * currentLink; 
} 

@property (retain, nonatomic) NSMutableString *currentLink; 

在您的实现:

在您didStartElement:

if ([elementName isEqualToString:@"item"]) { 
     self.isNewsItem = NO; 

     [item setObject:self.currentLink forKey:@"link"]; 
在foundCharacters

else if ([self.currentElement isEqualToString:@"link"]){ 
      self.newsLink = string; 
      [self.currentLink appendString:string]; 
     } 

在你的故事板:

if ([elementName isEqualToString:@"item"]) { 
     item = [[NSMutableDictionary alloc] init]; 
     self.currentLink = [[NSMutableString alloc] init]; 
     self.isNewsItem = YES; 
    } 
在didEndElement

嵌入您的表在nav控制器中的viewcontroller,从你的tableview添加一个push segue到详细视图,添加“detail”的标识符。

还对您的git进行了更改。

+0

@gabembev谢谢你的回答!我希望它能起作用! –

+0

我有一个SIGABRT错误。看看我的帖子在这里:[链接](http://stackoverflow.com/questions/22925618/loading-links-from-an-xml-file-onto-a-uiwebview-sigabrt-error) –