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.