I want to create object with parsed xml result, but it returns always null. I think it finished before nsxmlparser delegate does not complete.
This is my code.
@interface ParserOperation () <NSXMLParserDelegate, NSURLConnectionDelegate> {
NSString *soapResults;
NSXMLParser *xmlParser;
NSMutableData *responseData;
}
- (void)main {
NSError *error;
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self];
if (connection)
responseData = [NSMutableData data];
else
NSLog(@"NSURLConnection initWithRequest: Failed to return a connection.");
if ([self isCancelled]) {
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
self.callbackBlock(NO, error);
NSLog(@"error %@", error);
} else {
self.callbackBlock(YES, self.results);
NSLog(@"else %@", soapResults);
}
});
}
XML parser begins when NSURLConnection delegate methods are completed.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(@"Completed, Received Bytes:%lu",(unsigned long)[responseData length]);
xmlParser = [[NSXMLParser alloc] initWithData: responseData];
xmlParser.delegate = self;
[xmlParser setShouldResolveExternalEntities:YES];
[xmlParser parse];
}
- (void)parser:(NSXMLParser *) parser didStartElement:(NSString *) elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *) qName attributes:(NSDictionary *)attributeDict {
soapResults = [[NSString alloc] init];
}
- (void)parser:(NSXMLParser *) parser foundCharacters:(NSString *)string {
soapResults = [soapResults stringByAppendingString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:self.resultName]) {
if ([soapResults isEqualToString:@""]) {
NSLog(@"error");
}
else {
NSData *jsonData = [soapResults dataUsingEncoding:NSUTF8StringEncoding];
NSError *e;
self.results = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&e];
NSLog(@"Parsed Object: %@", self.results);
NSLog(@"soap: %@", soapResults);
}
}
}
There are two issues:
Wain's is absolutely correct, that this is asynchronous network request, so you need to make this a concurrent operation (+1), if it isn't already. Make sure (a) isConcurrent
returns YES
; (b) implement your own isExecuting
and isFinished
methods (or define BOOL
properties that will synthesize these getters for you); and (c) ensure you manually post the KVN for isFinished
and isExecuting
when you change the values. All of this is discussed in the Operation Queue chapter of the Concurrency Programming Guide. See the section titled "Configuring Operations for Concurrent Execution".
By the way, as Wain pointed out, because this is an asynchronous network request, you want to make sure you initiate the call back after the parsing in connectDidFinishLoading
.
You also cannot use delegate-based NSURLConnection
on an operation (assuming this operation is running on an operation queue) without scheduling this request on a run loop. The easiest solution is to just schedule the connection on the main run loop:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];
[connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
[connection start];
You can also create your own dedicated thread for NSURLConnection
(like AFNetworking does) and schedule your operations on that, but it adds some complexity.
The other approach I've seen people adopt (and it solves both the concurrent operation problem as well as the run loop problem) is to leave this as a non-concurrent operation, but have main
not only schedule the operation, but also create its own run loop. I'm not a fan of that technique, but it also works.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments