koen
koen

Reputation: 5731

AFNetworking: parsing xml in background

I think I am on the right track, but just wanted to double check here. I recently started using AFNetworking to obtain a large XML file from a database, which I then need to parse (I got that part all figured out). I would like the parsing to happen on a background thread, and then update my UI on the main thread. So I added another dispatch_async block inside the success block of the AFXMLRequestOperation:

self.xmlOperation =
[AFXMLRequestOperation XMLParserRequestOperationWithRequest: request
                                                    success: ^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) {

                                                        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                                                             XMLParser.delegate = self;
                                                            [XMLParser setShouldProcessNamespaces:YES];
                                                            [XMLParser parse];

                                                            dispatch_async(dispatch_get_main_queue(), ^{
                                                                [self.searchResultViewController didFinishImport];
                                                                [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];

                                                            });
                                                        });
                                                    }
                                                    failure: ^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParser) {
                                                        // show error
                                                    }];

[self.xmlOperation start];

Is the the proper/correct/preferred way to do this?

Upvotes: 1

Views: 803

Answers (1)

Rob
Rob

Reputation: 437917

This looks pretty good. Two observations, though:

  1. Does any of your code on the main thread can access any of the objects actively being updated by your NSXMLParserDelegate methods? If not, you're fine.

    But, if you have any code (driving the UI, for example) that is accessing the same objects/collections that the NSXMLParserDelegate methods are updating, then you have to be careful about synchronizing those shared resources. (For more information about synchronizing resources, see the Synchronization section of the Threading Programming Guide and/or the Eliminating Lock Based Code section of the Concurrency Programming Guide.)

    Personally, I like to move the NSXMLParserDelegate code into a separate class, and instantiate that for the individual request, that way I know that my request and subsequent parsing process can never be a source of synchronization issues. You still need to synchronize the update model/store process, but you are effectively doing that by performing that final update on the main queue.

  2. Does your UI allow you to issue another XML request while the first one is in progress? If not, you're fine.

    If the user can initiate second request while the first is in progress, it opens you up to the (admittedly unlikely) scenario that you could two concurrent processing requests using the same instance of the delegate object. Clearly, you could solve this by preventing subsequent requests until the first one finished (e.g. disable UI elements that request refresh), or use a serial queue, or move the parser into a separate class that you'll instantiate for every request. Personally, I'd be inclined to make make this parse request cancelable and make the issuance of a new request cancel any prior, on-going ones.

Those are two concurrency-related issues as I look at your code sample. Perhaps neither of these are, in fact, an issue with your particular implementation. Having said that, the very fact that the code is so contingent on the rest of your implementation is, itself, an issue.

Upvotes: 1

Related Questions