NSXMLParser Degelate Method 'parseErrorOccurred:' is Never Called on iOS 7

浪子不回头ぞ 提交于 2020-01-01 07:06:07

问题


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:

  1. NIKFeedParser - init
  2. NIKMasterViewController - viewDidLoad
  3. NIKFeedParser - startProcess
  4. NIKFeedParser - retrieveQueue
  5. NIKFeedParser - startProcess - [self.retrieverQueue addOperation:op];
  6. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!