NSXMLParser Degelate Method 'parseErrorOccurn:' никогда не вызывается на iOS 7
Я вырывал свои волосы более двух дней, чтобы решить эту проблему, и я так сильно сопротивлялся, чтобы не задавать вопрос здесь, так как раньше это могла быть чья-то проблема, но гуглил и читал все связанные вопросы на Stackoverflow вродеэто, или жеэто и читая больше учебников и тестируя различные примеры кода, я все еще не смог понять это.
У меня было приложение парсера RSS, которое работало довольно хорошо с тех пор, как оно было выпущено в магазине два года назад. Это простоNSXMLParser
реализации, и я использовал его во многих приложениях с тех пор, делая небольшие изменения, если это необходимо. Теперь я реализую тот же код в другом проекте, и он все еще работает нормально, но когда я выключаю Wi-Fi или использую недопустимый URL для анализа, он не выдает ошибкуiPhone Simulator
или жеiPhone 5, iOS 7.0.3
в то время как тот же код работает наiPhone 4S, iOS 6.1.3
Вот мой код:
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
и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
и мой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];
}
Установка точек останова для основных методов и отслеживание кода, это порядок вызова методов:
NIKFeedParser - init
NIKMasterViewController - viewDidLoad
NIKFeedParser - startProcess
NIKFeedParser - retrieveQueue
NIKFeedParser - startProcess - [self.retrieverQueue addOperation:op];
NIKMasterViewController - viewDidLoad
и тогда у меня есть контроллер представления таблицы банка и, очевидно, НЕ видимый индикатор сети, так как Wi-Fi выключен, в то время как ранее он мог отображатьUIAlertView
говорит мне, что произошла ошибка соединения. Что Apple изменила в новой iOS или SDK? Или чего мне не хватает?