问题
I have been pulling out my hair for more than two days to fix this problem, and I was resisting so badly not to ask a question here since it might be someone else's problem before, but googling and reading all related questions on Stackoverflow like this, or this and reading more tutorials and testing different sample codes, I still haven't been able to figure this out.
I had an RSS parser app that has been working pretty well since it was released on the store two years ago. It's a simple NSXMLParser
implementation and I've used it on many applications since then, making minor changes if needed. Now I'm implementing the same code on another project and it still works fine, but when I turn the wifi off or use an invalid url to parse, it doesn't throw an error on iPhone Simulator
or iPhone 5, iOS 7.0.3
, while the same code works fine on iPhone 4S, iOS 6.1.3
Here's my code:
NIKFeedParser.h
:
#import <Foundation/Foundation.h>
#import "NIKFeedEntry.h"
@class NIKFeedEntry;
@protocol NIKFeedParserDelegate;
@interface NIKFeedParser : NSObject <NSXMLParserDelegate>
{
NIKFeedEntry *currentItem;
NSMutableString *currentItemValue;
NSMutableArray *feedItems;
id<NIKFeedParserDelegate> delegate;
NSOperationQueue *retrieverQueue;
NSUInteger parsingFeedsWithNumbers;
NSOperationQueue *queue;
}
@property (strong, nonatomic) NIKFeedEntry *currentItem;
@property (strong, nonatomic) NSMutableString *currentItemValue;
@property (readonly) NSMutableArray *feedItems;
@property (strong, nonatomic) id<NIKFeedParserDelegate> delegate;
@property (strong, nonatomic) NSOperationQueue *retrieverQueue;
@property (nonatomic) NSUInteger parsingFeedsWithNumbers;
@property (strong, nonatomic) NSOperationQueue *queue;
@property (nonatomic) NSString *selectedCategory;
- (void) startProcess;
@end
@protocol NIKFeedParserDelegate <NSObject>
- (void) processCompleted;
- (void) processHasErrors;
@end
and the NIKFeedParser.m
:
#import "NIKFeedParser.h"
@implementation NIKFeedParser
@synthesize currentItem;
@synthesize currentItemValue;
@synthesize feedItems;
@synthesize delegate;
@synthesize retrieverQueue;
@synthesize parsingFeedsWithNumbers;
@synthesize queue;
@synthesize selectedCategory;
- (id) init
{
if (![super init])
{
return nil;
}
feedItems = [[NSMutableArray alloc] init];
queue = [NSOperationQueue new];
return self;
}
- (NSOperationQueue *)retrieverQueue
{
if (nil == retrieverQueue)
{
retrieverQueue = [[NSOperationQueue alloc] init];
retrieverQueue.maxConcurrentOperationCount = 1;
}
return retrieverQueue;
}
- (void) startProcess
{
SEL method = @selector (fetchAndParseFeed);
[[self feedItems] removeAllObjects];
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:method object:nil];
[self.retrieverQueue addOperation:op];
}
- (BOOL)fetchAndParseFeed
{
parsingFeedsWithNumbers = 0;
@autoreleasepool {
//NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
//To suppress the leak in NSXMLParser.
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
NSString *file = [[NSBundle mainBundle] pathForResource:@"Feed" ofType:@"plist"];
NSDictionary *item = [[NSDictionary alloc]initWithContentsOfFile:file];
NSArray *array = [item objectForKey:@"Root"];
NSURL *url = [NSURL URLWithString:
[[array objectAtIndex:[selectedCategory intValue]]objectForKey:@"URL"]];
BOOL success = NO;
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[parser setDelegate:self];
[parser setShouldProcessNamespaces:YES];
[parser setShouldReportNamespacePrefixes:YES];
[parser setShouldResolveExternalEntities:NO];
success = [parser parse];
return success;
}
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
{
if(nil != qualifiedName)
{
elementName = qualifiedName;
}
//NSLog(@"elementName: %@", elementName);
if ([elementName isEqualToString:@"item"])
{
self.currentItem = [[NIKFeedEntry alloc] init];
parsingFeedsWithNumbers++;
}
else if([elementName isEqualToString:@"title"] ||
[elementName isEqualToString:@"description"] ||
[elementName isEqualToString:@"link"] ||
[elementName isEqualToString:@"guid"] ||
[elementName isEqualToString:@"author"]||
[elementName isEqualToString:@"pubDate"])
{
self.currentItemValue = [NSMutableString string];
}
else
{
self.currentItemValue = nil;
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(nil != self.currentItemValue){
[self.currentItemValue appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if(nil != qName)
{
elementName = qName;
}
if([elementName isEqualToString:@"title"])
{
self.currentItem.podcastTitle = self.currentItemValue;
// int titleLength = [self.currentItem.title length];
// int len = (titleLength > 70) ? 70: titleLength;
// self.currentItem.shortTitle = [self.currentItem.title substringWithRange:NSMakeRange(0, len)];
}
else if([elementName isEqualToString:@"link"])
{
self.currentItem.podcastURL = self.currentItemValue;
}
else if([elementName isEqualToString:@"guid"])
{
// self.currentItem.guidUrl = self.currentItemValue;
}
else if ([elementName isEqualToString:@"author"])
{
// self.currentItem.author = self.currentItemValue;
}
else if([elementName isEqualToString:@"pubDate"])
{
// self.currentItem.podcastDate = self.currentItemValue;
// self.currentItem.pubDate = [FarsiNumbers convertNumbersToFarsi:self.currentItemValue];
}
else if([elementName isEqualToString:@"item"])
{
[[self feedItems] addObject:self.currentItem];
}
}
- (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock{
//CDATAblock implementation
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{
NSLog(@"parseErrorOccurred");
if(parseError.code != NSXMLParserDelegateAbortedParseError) {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[(id)[self delegate] performSelectorOnMainThread:@selector(processHasErrors)
withObject:nil
waitUntilDone:NO];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
NSLog(@"parserDidEndDocument");
//TitleViewController *viewController = [[TitleViewController alloc] init];
//viewController.parseFinished = @"1";
// parseFinished = [[NSString alloc] initWithFormat:@"%d", 1];
// NSLog(@"rss parser parser finished, %@", viewController.parseFinished);
parsingFeedsWithNumbers = 0;
[(id)[self delegate] performSelectorOnMainThread:@selector(processCompleted)
withObject:nil
waitUntilDone:NO];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
@end
and my NIKMasterViewController.m
:
- (void)viewDidLoad
{
feedParser = [[NIKFeedParser alloc] init];
[[self feedParser] setSelectedCategory:[self selectedCategory]];
[[self feedParser] setDelegate:self];
[[self feedParser] startProcess];
}
- (void)processCompleted
{
[[self tableView] reloadData];
[activityIndicator stopAnimating];
NSInteger rowCount = [[[self feedParser] feedItems] count];
if (rowCount!=0) {
//
self.tableView.delegate = self;
self.tableView.dataSource = self;
}
else if ((rowCount==0) &&([UIApplication sharedApplication].networkActivityIndicatorVisible == NO ) ){
UILabel *noContentWarning = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 480, 480)];
noContentWarning.text = NO_CONTENT_WARNING_MESSAGE;
noContentWarning.center = CGPointMake(self.view.frame.size.width/2, self.view.frame.size.height/3);
}
}
- (void)processHasErrors
{
//Due to internet connection or server error.
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NO_CONNECTION_ALERT_TITLE message: NO_CONNECTION_ALERT_MESSAGE delegate:self cancelButtonTitle:NO_CONNECTION_ALERT_VIEW_DISMISS_BUTTON otherButtonTitles:nil];
[alert show];
[activityIndicator stopAnimating];
}
Setting breakpoints on the main methods and tracing the code, this is the order the methods are called:
NIKFeedParser - init
NIKMasterViewController - viewDidLoad
NIKFeedParser - startProcess
NIKFeedParser - retrieveQueue
NIKFeedParser - startProcess - [self.retrieverQueue addOperation:op];
NIKMasterViewController - viewDidLoad
and then I have the bank table view controller and obviously NOT a visible network indicator since the wifi is off, while previously, it was able to display a UIAlertView
telling me there's a connection error occurring. What has Apple changed in the new iOS or SDK? Or what am I missing?
来源:https://stackoverflow.com/questions/19752793/nsxmlparser-degelate-method-parseerroroccurred-is-never-called-on-ios-7