4

I'm trying to implement downloading of a large file and show to user current progress, but block in:

-[AFURLConnectionOperation setDownloadProgressBlock:] 

returns incorrect bytesRead and totalBytesRead values (they are smaller than they should be).

For example: If I have a 90MB file and when it downloads completely, latest block invocation in setDownloadProgressBlock: gives me totalBytesRead value about 30MB. On other side, if file is 2MB large, latest block invocation gives correct totalBytesRead 2MB value.

AFNetworking is updated to the latest version from github.
If AFNetworking can't do it correctly, what solution can I use?

Edit: I've determined that even if file is not downloaded completely (and this happens every time with relatively big file) AFNetworking calls success block in:

-[AFHTTPRequestOperation setCompletionBlockWithSuccess:failure:]

I asked a similar question here about this situation, but didn't get any answers.
I can check in code downloaded and real file sizes, but AFNetworking has no API for continuation of partial download.

Community
  • 1
  • 1
Alexander
  • 780
  • 1
  • 8
  • 22

2 Answers2

12

I have no problems with the setDownloadProgressBlock in AFNetworking.

The wiki explains how to track download progress: https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ

For progress tracking you don't need the bytesRead (number of bytes written in a particular callback).

Example code:

[downloadoperation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
        float progress = ((float)totalBytesRead) / totalBytesExpectedToRead;
        self.progressView.progress = progress;
    }];
Felix
  • 35,354
  • 13
  • 96
  • 143
  • Yes, I understand, my code is identical to yours. I'm only saying that bytesRead also gives incorrect number on large files. – Alexander Nov 03 '12 at 19:05
  • can you give an example? as I said you can ignore `bytesRead` because it is not relevant for progress. – Felix Nov 03 '12 at 19:29
  • what do you get with `NSLog(@"%u %llu %llu", bytesRead, totalBytesRead, totalBytesExpectedToRead);`? bytesRead should be more or less the same value in each callback. – Felix Nov 03 '12 at 19:36
  • I've added an example to my question to clarify it. If I sum on every block invocation `bytesRead` it will give value equal to `totalBytesRead`, incorrect value in other words. – Alexander Nov 03 '12 at 20:07
  • 2
    AFNetworking does it correctly, look at the source: https://github.com/AFNetworking/AFNetworking/blob/master/AFNetworking/AFURLConnectionOperation.m#L542 Obviously the connection is cancelled too early, maybe because there is not enough disk space. I assume you have setup a NSOutputStream that writes to file. Otherwise you would consume very much memory and iOS may cancel the download because of that. – Felix Nov 03 '12 at 21:13
  • From the AFNetworking wiki: **How do I download a file?** Use the outputStream property of AFURLConnectionOperation or its subclasses, setting it to an NSOutputStream that streams to a file at a specified path: `operation.outputStream = [NSOutputStream outputStreamToFileAtPath:@"download.zip" append:NO];` This is especially useful when you're downloading anything relatively large (more than a few MB), since the contents of the file will be streamed directly to the file, rather than being stored in memory. – Felix Nov 03 '12 at 21:15
  • I've used `outputStream`, but in some sense you are right, file is not downloaded completely to disk. I've updated my question, there are some explanations. – Alexander Nov 03 '12 at 22:36
1

phix23 answered to my initial question, so there is really no problem with progress block. I'm answering to my edit.

When success block in

-[AFHTTPRequestOperation setCompletionBlockWithSuccess:failure:]

is called, I can compare the number of bytes downloaded with the number of bytes expected to download (it is not very hard to implement in code). If the number of downloaded bytes is smaller - I can continue file download from place where it was interrupted. To do this, I'm using Range http header in NSURLRequest, here is more information:
Continue an interrupted download on iPhone
How to implement resumable file downloads on iPhone SDK

So, the problem is not really with AFNetworking (NSURLConnection has same behavior), but, I think, developers of the framework could take into account this situation.

Community
  • 1
  • 1
Alexander
  • 780
  • 1
  • 8
  • 22
  • ~goodfella "I can compare the number of bytes downloaded with the number of bytes expected to download. (it is not very hard to implement in code). " Could you please elaborate in code? How do you get number of bytes expected? I am having trouble finding such an API from AFNetworking – Erika Electra Mar 06 '16 at 02:02
  • You can find example code in the following class: https://github.com/onivem/Download, particularly in setCompletionBlocks method. Note that this class has been written for AFNetworking as it was on may 2013. – Alexander Mar 07 '16 at 16:17