iOS AFNetworking download Расчет ProgressBlock, возвращающий отрицательные числа

Я использую AFNetworking для загрузки данных, которые анализируются сторонним классом. Я использовал AFNetworking для выполнения подобных действий много раз раньше, но по какой-то причине, когда я вызываю downloadProgressBlock и выполняю вычисления для использования с моим индикатором выполнения, числа возвращаются отрицательными. Смотри ниже:

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

Ниже мой код:

// 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];

person Jon Erickson    schedule 22.09.2013    source источник


Ответы (1)


Я подозреваю, что вы обнаружите, что проблема в totalBytesExpectedToRead. В частности, это происходит из свойства NSURLResponse, expectedContentLength, которое как говорится в документации:

Возвращаемое значение

Ожидаемая длина содержимого получателя или NSURLResponseUnknownLength, если длина не может быть определена.

Обсуждение

Некоторые реализации протокола сообщают длину содержимого как часть ответа, но не все протоколы гарантируют доставку такого объема данных. Клиенты должны быть готовы работать с большим или меньшим количеством данных.

Кстати, эта константа NSURLResponseUnknownLength равна -1, что объясняет ваши расчетные значения. Именно так система информирует вас о том, что ей не удалось определить длину ответа.

Таким образом, в худшем случае вы получите -1 как ожидаемое количество байтов. Даже если это не -1, это не совсем надежно (особенно проблема, если вы написали свой собственный серверный код). Ваше приложение должно изящно обрабатывать все expectedContentLength, сообщаемые вашему приложению. В большинстве случаев, если вы получаете неотрицательное значение, вы обычно получаете значение, которое можно эффективно использовать для вычисления «процента завершения», но не полагайтесь на него (например, вы можете получить больше байтов). или меньше байт, чем сообщает expectedContentLength). Изящно обрабатывать исключительные значения.

Например, при настройке индикатора выполнения я сделал что-то вроде:

CGFloat progress;

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

Это дает мне индикатор выполнения, который медленно прогрессирует до 100% по мере продолжения загрузки, если у меня есть хорошее ожидаемое значение длины содержимого, но в противном случае показывает мне индикатор выполнения, который прогрессирует от 0% до 100% для каждого загруженного 1 000 000 байтов. Этот последний сценарий не идеален, но вы мало что можете сделать, если ваш сервер не сообщает точную ожидаемую длину контента.

В качестве альтернативы, если вы никогда не получите надежного expectedContentLength, вы можете использовать неопределенное представление прогресса (например, UIActivityIndicatorView), которое вообще позволяет избежать этой проблемы.

Суть в том, что успешное вычисление прогресса зависит от того, предоставляет ли ваш сервер законное значение для ожидаемых байтов. Если вы посмотрите на totalBytesExpectedToRead, держу пари, вы получите -1 и в результате увидите свои любопытные расчетные процентные значения прогресса.

person Rob    schedule 23.09.2013
comment
Да, это оно. Спасибо за подробный ответ. - person Jon Erickson; 23.09.2013