سؤال

I must be overlooking something silly. I am using AFNetworking to perform an HTTP GET request which returns XML content. When the request returns my success block executes. I am using NSXMLParser to parse the XML and return the result.

I know that NSXMLParser's parse method is synchronous and it should block until the XML parsing is complete. This works as I'd expect in my unit tests. However in the context of my success block it appears to call NSXMLParser:parse and then continue execution. I am passing the (initialized) parser to an object which is the NSXMLParser delegate. The parsing is called within this object to initialize member data. So I need the parsing to complete before the block completes execution.

So my parsing object looks like this:

    @interface Content : NSObject <NSXMLParserDelegate>

@property (readonly) NSXMLParser *xmlParser;
@property (readonly) NSString *documentTitle;
@property (readonly) NSMutableArray *sectionTitles;
@property (readonly) NSString *documentFormat;
@property (readonly) NSString *localization;
@property (readonly) NSString *contentVersion;

- (id)initWithParser:(NSXMLParser *)xmlParser;
- (BOOL)parse;

@end

This object's "parse" method simple calls NSXMLParser:parse

-(BOOL)parse{
NSLog(@"%@", @"calling parse");//this is in the output
return [xmlParser parse]; // return parse success or error

};

In my service call I am calling the constructor on this object and providing the NSXMLParser. Then I immediately call this object's "parse" method. However the block seems to call parse and continue execution (like an asynchronous call) and return this object uninitialized.

-(void)makeHttpRequest:(NSURL *)url
             onSuccess:(ContentSuccess)success //this a block that client code passes in are blocks
             onFailure:(ContentFailure)failure{
    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]initWithRequest:request];
    [operation  setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSXMLParser *xmlParser = [[NSXMLParser alloc]initWithData:responseObject];
        Content *content = [[Content alloc]initWithParser:xmlParser];
        [content parse]; // this gets called but it's not blocking
        success(kbContent); // this gets called right away with ivar == nil
    }
                                      failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                                          failure(error);

                                      }
     ];
    [operation start];

}

This must have something to do with my block implementation.. like I said the [content parse] seems to work synchronously in my unit tests. But they are not run in the context of a block. Can anyone offer some advice?

Thanks!

update

It seems that my Content:parse method was returning 'NO' which would indicate a parse error. However the NSXMLParser.pasererror was 'nil'. If I simple pass back the NSXMLParser object back from the success block and THEN parse it has no problems. In the block none of the Parser delegate methods are ever called. Strange.

هل كانت مفيدة؟

المحلول

If an NSXMLParser instance is returning from parse without calling any delegate methods, then likely it encountered an error. Check the return value of parse (it will return NO if it fails) as well as the parserError method (which returns an NSError if one's been set). It's not impossible that the parser set an error but still succeeded, so make sure to base your decisions on the return value, not the presence of an error (this is an established Cocoa convention).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top