Showing the file download progress with NSURLSessionDataTask Showing the file download progress with NSURLSessionDataTask ios ios

Showing the file download progress with NSURLSessionDataTask


You need to implement following delegates:

<NSURLSessionDataDelegate, NSURLSessionDelegate, NSURLSessionTaskDelegate>

Also need to create two properties:

@property (nonatomic, retain) NSMutableData *dataToDownload;@property (nonatomic) float downloadSize;- (void)viewDidLoad {    [super viewDidLoad];    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];    NSURL *url = [NSURL URLWithString: @"your url"];    NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithURL: url];    [dataTask resume];}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {    completionHandler(NSURLSessionResponseAllow);    progressBar.progress=0.0f;    _downloadSize=[response expectedContentLength];    _dataToDownload=[[NSMutableData alloc]init];}- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {    [_dataToDownload appendData:data];    progressBar.progress=[ _dataToDownload length ]/_downloadSize;}


You can also use NSURLSessionDownloadTask like following. Call startDownload methode.In .h file use this

- (void)startDownload{    NSString *s;    s = @"http://www.nasa.gov/sites/default/files/styles/1600x1200_autoletterbox/public/pia17474_1.jpg?itok=4fyEwd02";    NSURLSessionDownloadTask *task = [self.session downloadTaskWithURL:[NSURL URLWithString:s]];    [task resume];}- (NSURLSession *) configureSession {    NSURLSessionConfiguration *config =    [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.neuburg.matt.ch37backgroundDownload"];    config.allowsCellularAccess = NO;    // ... could set config.discretionary here ...    NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];    return session;}-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {    CGFloat prog = (float)totalBytesWritten/totalBytesExpectedToWrite;    NSLog(@"downloaded %d%%", (int)(100.0*prog));}-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes {    // unused in this example}-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {    NSData *d = [NSData dataWithContentsOfURL:location];    UIImage *im = [UIImage imageWithData:d];    dispatch_async(dispatch_get_main_queue(), ^{        self.image = im;    });}-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {    NSLog(@"completed; error: %@", error);}


Since iOS 11.0 and macOS 10.13, URLSessionTask (former NSURLSessionTask) adopted the ProgressReporting protocol. That means you can use the progress property to track the progress of a session task.

Expecting you already know how to use KVO observers, you can do something like:

task = session.downloadTask(with: url)task.resume()task.progress.addObserver(self, forKeyPath: "fractionCompleted", options: .new, context: &self.progressKVOContext)

and observe the value with:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {    if context == &self.progressKVOContext, let keyPath = keyPath {        switch keyPath {        case "fractionCompleted":            guard let progress = object as? Progress else {                return            }            DispatchQueue.main.async { [weak self] in                self?.onDownloadProgress?(progress.fractionCompleted)            }        case "isCancelled":            cancel()        default:            break        }    }    else {        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)    }}

iOS 13 update

OperationQueue has now a progress property.

For example, the UIProgressView can observe that property and update the progress value automatically using the observedProgress. Full example in https://nshipster.com/ios-13/#track-the-progress-of-enqueued-operations.