Setting progress of ProgressView while parsing XML
I am parsing using an XML file. I want to show a Progress Bar till the par开发者_开发技巧sing procedure completes. How can I calculate the progress of the ProgressView ?? Pls Help..
First, count the number of lines.
NSError *error = nil;
NSString *xmlFileString = [NSString stringWithContentsOfURL:url
encoding:NSUTF8StringEncoding error:&error];
_totalLines = [xmlFileString componentsSeparatedByString:@"\n"].count;
Then, catch the progress in delegate method block. For example:
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
[self.elementStack addObject:elementName];
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[mainQueue addOperationWithBlock:^{
_progressView.progress = (CGFloat)[parser lineNumber] / (CGFloat)_totalLines;
}];
}
Sample Project is Here:
https://github.com/weed/p120727_XMLParseProgress
If you are parsing with NSXMLParser
and know the length of the file being parsed, you can approximate progress by calling lineNumber
on your parser object to tell you how far through the file the parser is.
progressView.progress = (CGFloat)[parser lineNumber] / (CGFloat)totalLines;
I'm processing large files where it was taking several seconds to count how many lines there are in the file.
I came up with a more complex but faster solution:
- map the contents of the file into virtual memory, using NSData. This is the fastest way to read a large file on OS X and iOS. It will be loaded into RAM if it's a small/medium sized file, but large files will only partially be loaded into RAM.
- using grand central dispatch, fire off a background task to process the data in 10KB chunks, counting how many newlines are found.
- fire off another grand central dispatch task to parse the same
NSData
object. - whenever a new tag is started, every half a second, check if the line counting has finished, and if so it updates the progress bar.
Mapping a file into virtual memory and then seraching for newline bytes is around 10x faster than any other method I could find, including some low level C choices. It takes a split second to count a file with 3 million lines on my SSD equiped mac.
Doing it on a background thread, in parallel with NSXMLParser
on the same NSData
object, ensures the file will not be read from the disk twice (unless the file is too big to fit in RAM).
Source code for this is here: https://github.com/abhibeckert/Speed-Limit/blob/master/Speed%20Limit/SLOSMImporter.m
Note: the code I posted will work on iOS 7 and OS X 10.9. It has only been tested on OS X 10.9. It could be modified fairly easily to work on older versions of the SDK, just build it and the compile errors should be easy to fix.
精彩评论