質問

I am using AFNetworking to download data that is parsed with a third party class. I have used AFNetworking to do similar actions many times before but for some reason, when I call the downloadProgressBlock and do the calcuation to use with my progress bar, the numbers are returning negative. See below:

2013-09-22 16:04:06.036 Portland Police[2228:60b] Download = -31849.000000
2013-09-22 16:04:06.041 Portland Police[2228:60b] Download = -40537.000000
2013-09-22 16:04:06.042 Portland Police[2228:60b] Download = -44881.000000
2013-09-22 16:04:06.044 Portland Police[2228:60b] Download = -53569.000000
2013-09-22 16:04:06.046 Portland Police[2228:60b] Download = -62257.000000
2013-09-22 16:04:06.048 Portland Police[2228:60b] Download = -63705.000000
2013-09-22 16:04:06.085 Portland Police[2228:60b] Download = -70945.000000
2013-09-22 16:04:06.087 Portland Police[2228:60b] Download = -89769.000000
2013-09-22 16:04:06.089 Portland Police[2228:60b] Download = -94113.000000
2013-09-22 16:04:06.100 Portland Police[2228:60b] Download = -98457.000000
2013-09-22 16:04:06.104 Portland Police[2228:60b] Download = -102801.000000
2013-09-22 16:04:06.111 Portland Police[2228:60b] Download = 1.000000

Below is my code:

// Get the URL we are going to use to parse with
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:@"http://www.portlandonline.com/scripts/911incidents.cfm"]];
NSURLRequest *request = [httpClient requestWithMethod:@"GET" path:nil parameters:nil];
AFHTTPRequestOperation *operation = [httpClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {

    NSLog(@"Response = %@", operation);

    // Empty our calls out
    [self.originalArray removeAllObjects];

    // Initiate our parser
    MWFeedParser *parser = [[MWFeedParser alloc] init];
    parser.delegate = self;
    [parser startParsingData:responseObject textEncodingName:[operation.response textEncodingName] withCompletionHandler:^(NSError *error, MWFeedParser *parser) {

        // If theres no error
        if (!error) {

            // Return the success block
            success(operation.request, operation.request.URL, self.calls);
        }
        else {

            // Return the failure block
            failure(operation.request, operation.request.URL, error);
        }
    }];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

    NSLog(@"AFHTTPRequestOperation Failure: %@", error);

    // Return our failure block
    failure(operation.request, operation.request.URL, error);
}];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {

    NSLog(@"Download = %f", (float)totalBytesRead / totalBytesExpectedToRead);

}];
[operation start];
役に立ちましたか?

解決

I suspect you'll find the problem is totalBytesExpectedToRead. Specifically, this comes from the NSURLResponse property, expectedContentLength, which as the docs say:

Return Value

The receiver’s expected content length, or NSURLResponseUnknownLength if the length can’t be determined.

Discussion

Some protocol implementations report the content length as part of the response, but not all protocols guarantee to deliver that amount of data. Clients should be prepared to deal with more or less data.

By the way, this constant, NSURLResponseUnknownLength, is equal to -1, which would explain your calculated values. This is just the way the system informs you that it was unable to determine the length of the response.

So, in the worst case scenario, you'll be getting -1 as a number of bytes expected. Even if it's not -1, it is not entirely reliable (especially an issue if you have written your own server code). Your app must gracefully handle whatever expectedContentLength is reported to your app. Most of the time, if you're getting a non-negative value, you're generally getting a value that can be used effectively for a "percent complete" calculation, but don't rely upon it (e.g. you may receive more bytes or less bytes than expectedContentLength reports). Gracefully handle exceptional values.

For example, when setting my progress bar, I've done something like:

CGFloat progress;

if (expectedContentLength > 0 && progressContentLength <= expectedContentLength)
     progress = (CGFloat) progressContentLength / expectedContentLength;
else
     progress = (progressContentLength % 1000000l) / 1000000.0f;

This gives me a progress bar that progresses slowly to 100% as the download proceeds if I've got good expected content length value, but otherwise shows me a progress bar that progresses from 0% to 100% for every 1,000,000 bytes downloaded. This latter scenario is not ideal, but there's not a lot you can do unless your server reports an accurate expected content length.

Alternatively, if you never get a reliable expectedContentLength, you might choose to use an indeterminate progress view (e.g. UIActivityIndicatorView) which avoids this problem altogether.

Bottom line, the successful calculation of progress is contingent upon your server is providing a legitimate value for bytes expected. If you look at totalBytesExpectedToRead, I'd bet you're getting -1, and seeing your curious calculated progress percentage values as a result.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top