2014-04-08 57 views
0

我一直在試圖解析XML文件以便從使用後臺獲取的網站獲取文章。將XML文件中的鏈接加載到UIWebView(SIGABRT錯誤)

有人給我回答了這個問題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 

DetailViewCon troller.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" 。

感謝任何人的幫助!

崩潰日誌

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

    }]; 
} 
+0

我們可以看到崩潰日誌嗎? – NobodyNada

+0

@NobodyNada我將提供作業的崩潰日誌。 –

+0

@NobodyNada我將如何提供崩潰日誌? –

回答

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]; 
+0

感謝您的答案。我的代碼現在正在編譯。但是,每個新聞項目都不會加載鏈接。什麼似乎是問題? –

+0

對不起,但我對網絡相關的東西和故事板幾乎一無所知。 – NobodyNada

+0

好的。感謝您幫我解決我的SIGABRT錯誤。 –

1

好吧..再看看你的代碼。

一些遺失的東西。

在你NewsViewController.h

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

需要包括數組和MutableArray

而且在NewsViewController.h

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

添加的屬性在實現文件中。

@synthesize items, itemArray; 

在你XMLParser的實施

@synthesize currentLink; 

最後在你的故事板,您在SEGUE從視圖控制器,而不是電池單元排到來。

刪除當前的segue並將另一個從單元格添加到DetailViewController視圖。

我推動了更改。

+0

感謝您的答覆,我希望它的作品! –