将XML文件中的链接加载到UIWebView(SIGABRT错误)

时间:2014-04-08 00:42:11

标签: ios objective-c xml uitableview uiwebview

我一直在尝试解析XML文件,以便使用后台获取从网站上获取文章。

有人给了我这个问题的答案here

然而,他的回答导致了SIGABRT错误。

有人可以查看我的代码,看看我的问题是什么?提前谢谢。

我的代码:

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;
 }

 - (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];

     }
 }


 -(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> {
NSMutableDictionary *item;
NSMutableString * currentLink;
}

@property (retain, nonatomic) NSMutableString *currentLink;

-(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"]) {
     item = [[NSMutableDictionary alloc] init];
     self.currentLink = [[NSMutableString alloc] init];
     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;

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


         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;
             [self.currentLink appendString: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

DetailViewController.h(这是包含我的UIWebView的uiviewcontroller的文件):

 #import <UIKit/UIKit.h>

 @interface DetailViewController : UIViewController<UIWebViewDelegate> {
     NSDictionary *item;
 }

 @property (retain, nonatomic) NSDictionary *item;
 @property (retain, nonatomic) IBOutlet UIWebView *itemSummary;

 @end

DetailViewController.m:

 #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

如果您想自己运行该项目,可以在Github上找到它here

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

感谢任何有帮助的人!

CRASH LOG

2014-04-08 16:33:05.611 Your Guide to TF2[499:70b] -[UINavigationController fetchNewDataWithCompletionHandler:]: unrecognized selector sent to instance 0x1090aa930
2014-04-08 16:33:05.755 Your Guide to TF2[499:70b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UINavigationController fetchNewDataWithCompletionHandler:]: unrecognized selector sent to instance 0x1090aa930'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010189a795 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x00000001015fd991 objc_exception_throw + 43
    2   CoreFoundation                      0x000000010192bbad -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
    3   CoreFoundation                      0x000000010188c09d ___forwarding___ + 973
    4   CoreFoundation                      0x000000010188bc48 _CF_forwarding_prep_0 + 120
    5   Your Guide to TF2                   0x0000000100004819 -[AppDelegate application:performFetchWithCompletionHandler:] + 345
    6   UIKit                               0x000000010026e0b5 -[UIApplication _handleOpportunisticFetchWithSequenceNumber:] + 170
    7   UIKit                               0x000000010025b200 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1761
    8   UIKit                               0x000000010025ebe8 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 660
    9   UIKit                               0x000000010026faab -[UIApplication handleEvent:withNewEvent:] + 3092
    10  UIKit                               0x000000010026ff1e -[UIApplication sendEvent:] + 79
    11  UIKit                               0x00000001002602be _UIApplicationHandleEvent + 618
    12  GraphicsServices                    0x00000001039a2bb6 _PurpleEventCallback + 762
    13  GraphicsServices                    0x00000001039a267d PurpleEventCallback + 35
    14  CoreFoundation                      0x000000010181c819 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 41
    15  CoreFoundation                      0x000000010181c5ee __CFRunLoopDoSource1 + 478
    16  CoreFoundation                      0x0000000101845ab3 __CFRunLoopRun + 1939
    17  CoreFoundation                      0x0000000101844f33 CFRunLoopRunSpecific + 467
    18  UIKit                               0x000000010025e4bd -[UIApplication _run] + 609
    19  UIKit                               0x0000000100260043 UIApplicationMain + 1010
    20  Your Guide to TF2                   0x0000000100004ce3 main + 115
    21  libdyld.dylib                       0x0000000101f295fd start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

AppDelegate.m

 #import "AppDelegate.h"
 #import "NewsViewController.h"
 #define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue &  0xFF))/255.0 alpha:1.0]

 @implementation AppDelegate

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
 {
     [application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
     // Override point for customization after application launch.
     // Uncomment to change the background color of navigation bar
     [[UINavigationBar appearance] setBarTintColor:UIColorFromRGB(0xb35326)];

     // Uncomment to change the color of back button
     //[[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];

     // Uncomment to assign a custom backgroung image
     //[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"tf2_logo.png"] forBarMetrics:UIBarMetricsDefault];

     // Uncomment to change the back indicator image
     /*
      [[UINavigationBar appearance] setBackIndicatorImage:[UIImage imageNamed:@"back_btn.png"]];
      [[UINavigationBar appearance] setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"back_btn.png"]];
      */

     // Uncomment to change the font style of the title
     /*
      NSShadow *shadow = [[NSShadow alloc] init];
 shadow.shadowColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.8];
      shadow.shadowOffset = CGSizeMake(0, 1);
      [[UINavigationBar appearance] setTitleTextAttributes: [NSDictionary dictionaryWithObjectsAndKeys:
      [UIColor colorWithRed:245.0/255.0 green:245.0/255.0 blue:245.0/255.0 alpha:1.0], NSForegroundColorAttributeName,
 shadow, NSShadowAttributeName,
      [UIFont fontWithName:@"HelveticaNeue-CondensedBlack" size:21.0], NSFontAttributeName, nil]];
      */


     return YES;
 }

 -(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
     NSDate *fetchStart = [NSDate date];

NewsViewController *viewController = (NewsViewController *)self.window.rootViewController;

[viewController fetchNewDataWithCompletionHandler:^(UIBackgroundFetchResult result) {
    completionHandler(result);

    NSDate *fetchEnd = [NSDate date];
    NSTimeInterval timeElapsed = [fetchEnd timeIntervalSinceDate:fetchStart];
    NSLog(@"Background Fetch Duration: %f seconds", timeElapsed);

     }];
 }

2 个答案:

答案 0 :(得分:1)

问题出在-[AppDelegate application:performFetchWithCompletionHandler:] 这条线错了:

NewsViewController *viewController = (NewsViewController *)self.window.rootViewController;

根视图控制器是UINavigationController,但您假设它是NewsViewController。那应该是:

UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
NewsViewController *viewController = (NewsViewController *)[[navController viewControllers] objectAtIndex:0];

答案 1 :(得分:1)

好的..再看看你的代码。

缺少一些东西。

在NewsViewController.h中

@interface NewsViewController : UIViewController<UITableViewDelegate, UITableViewDataSource>{
    NSArray *items;
    NSMutableArray *itemArray;
}

需要包含Array和MutableArray

还在NewsViewController.h中添加属性

@property (retain, nonatomic) NSArray *items;
@property (retain, nonatomic) NSMutableArray *itemArray;

在您的实施文件中。

@synthesize items, itemArray;

在XMLParser实现中

@synthesize currentLink;

最后在你的故事板上,你有来自视图控制器而不是单元格行的segue。

删除当前的segue,并将另一个来自单元格的视图添加到DetailViewController视图中。

我也推动了这些变化。