开发者

NSOperation will not cancel NSXMLParser. Which continues to call methods on delegate causing crash

I am trying to download some XML on another thread, and parse it.

I release the 'controller' then call cancelAllOperations on the NSOperationQueue. And implement method 'cancel' on NSoperation which attempts to set nSXMLParser's delegate to nil.

But a second or so later the NSXMLParser is still alive and kicking and calls methods on it's d开发者_C百科elegate (which now no longer exists) causing a crash.

I just dont get it, what am I doing wrong?

#import "LoadXMLTheadedController.h"
#import "LoadXMLThreaded.h"


 @implementation LoadXMLTheadedController


- (id)initWithURLString:(NSString *)newString
{self = [super init]; 

queue  = [[NSOperationQueue alloc] init];

loadXMLThreaded = [[LoadXMLThreaded alloc] initWithDelegate:self andXMLURLString:newString];

[queue addOperation:loadXMLThreaded];

return self;
}


- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName     namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
    NSLog(@" do some parsing.. ");

}


- (void)dealloc {

[[NSNotificationCenter defaultCenter] removeObserver:self];
[queue cancelAllOperations];

[loadXMLThreaded release];
[queue release];
[super dealloc];
}
@end

//----------------------------------------------------------------//

#import "LoadXMLThreaded.h"

@implementation LoadXMLThreaded



- (id)initWithDelegate:(id)newDelegate andXMLURLString:(NSString *)newString
{
[super init];

delegate = newDelegate;
url = [[NSURL URLWithString:newString]retain];

return self;
}


- (void)cancel{

nSXMLParser.delegate = nil;
[nSXMLParser abortParsing];

 }
- (void)main {


nSXMLParser = [[NSXMLParser alloc]initWithContentsOfURL:url];
nSXMLParser.delegate = delegate;
[nSXMLParser parse];    
}

 - (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
nSXMLParser.delegate = nil;
[nSXMLParser abortParsing];
[nSXMLParser release];
[url release];
[super dealloc];
}
@end


The NSOperation's cancel method simply sets a flag. It does not forcibly halt the NSOperation itself. The user is responsible for implementing the necessary code to stop whatever's running at the moment.

You would need to check periodically to see if the cancel flag is set, then call abort on NSXMLParser yourself.


I know I'm late to the party with this one, but thought I'd put in my 2 cents. Going off of @futureelite7, you should never override the cancel method.

Instead, throughout your NSOperation's subclass, you should periodically verify if the operation is cancelled by using isCancelled and act accordingly. In this case, we want to abort the parsing.

For example, after your NSXMLParser delegate methods, make this the first line in the method:

// make your parser an ivar
if ([self isCancelled]) [operationParser abortParsing];

In addition, I recommend making your NSOperation the NSXMLParser delegate, so all parsing is encapsulated within your NSOperation subclass.

And lastly, just an fyi, aborting parsing will cause an error with code NSXMLParserDelegateAbortedParseError. Just be aware of it during error handling.


Apple's documentation:

abortParsing

Stops the parser object.

- (void)abortParsing

Discussion

If you invoke this method, the delegate, if it implements parser:parseErrorOccurred:, is informed of the cancelled parsing operation.

I'm just guessing. Normally sending a method to nil isn't a problem in Objective-C. But maybe NSXMLParser does something fancy internally.

General remarks about your code

  • Learn how to write the init method correctly.
  • You don't have to set the delegate of an object to nil that is going to be deallocated anyway.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜