get progress from dataTaskWithURL in swift
you can use this code for showing download process with progress bar with its delegate functions.
import UIKit
class ViewController: UIViewController,NSURLSessionDelegate,NSURLSessionDataDelegate{
@IBOutlet weak var progress: UIProgressView!
var buffer:NSMutableData = NSMutableData()
var session:NSURLSession?
var dataTask:NSURLSessionDataTask?
let url = NSURL(string:"http://i.stack.imgur.com/b8zkg.png" )!
var expectedContentLength = 0
override func viewDidLoad() {
super.viewDidLoad()
progress.progress = 0.0
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let manqueue = NSOperationQueue.mainQueue()
session = NSURLSession(configuration: configuration, delegate:self, delegateQueue: manqueue)
dataTask = session?.dataTaskWithRequest(NSURLRequest(URL: url))
dataTask?.resume()
// Do any additional setup after loading the view, typically from a nib.
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
//here you can get full lenth of your content
expectedContentLength = Int(response.expectedContentLength)
println(expectedContentLength)
completionHandler(NSURLSessionResponseDisposition.Allow)
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
buffer.appendData(data)
let percentageDownloaded = Float(buffer.length) / Float(expectedContentLength)
progress.progress = percentageDownloaded
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
//use buffer here.Download is done
progress.progress = 1.0 // download 100% complete
}
}
Showing the file download progress with NSURLSessionDataTask
You need to implement following delegates:
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;
}
Find the Download Progress of a file in swift
The progress status can be calculated in
URLSession(_:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:)
This is a one of three required methods of protocol NSURLSessionDownloadDelegate. In my case the code of the method looks like this:
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
// println("download task did write data")
let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
dispatch_async(dispatch_get_main_queue()) {
self.progressDownloadIndicator.progress = progress
}
}
I've created a small project, which implements three different approaches:
- download synchronously
- download asynchronously
- download with progress
Check it out: http://goo.gl/veRkA7
How do I check the current progress of URLSession.dataTaskPublisher?
I mostly agree with @Rob, however you can control state of DataTask
initiated by DataTaskPublisher
and its progress by using of URLSession
methods:
func downloadData(_ req: URLRequest) {
URLSession.shared.getAllTasks { (tasks) in
let task = tasks.first(where: { (task) -> Bool in
return task.originalRequest?.url == req.url
})
switch task {
case .some(let task) where task.state == .running:
print("progress:", Double(task.countOfBytesReceived) / Double(task.countOfBytesExpectedToReceive))
return
default:
self.cancelToken = URLSession.shared.dataTaskPublisher(for: req).sink { /* ... */ }
}
}
}
Is it possible to use URL session delegate method for progress and completion handler for completion? Or better option?
Thanks to Faysal Ahmed, I managed to find the following solution that worked. This allowed me to track my progress to update UI whilst also using a completion handler.
observation = task.progress.observe(\.fractionCompleted) { progress, _ in
DispatchQueue.main.async(execute: {
self.globalScrollTitle.mainprogress = CGFloat(progress.fractionCompleted)
})
if progress.fractionCompleted == 1 {
completion()
}
}
My download func now looks like this:
func download(url: String, fileName: String, completion: @escaping () -> Void) {
let myUrl = URL(string: url)
let request = URLRequest(url:myUrl!)
let config = URLSessionConfiguration.default
let operationQueue = OperationQueue()
let session = URLSession(configuration: config, delegate: nil, delegateQueue: operationQueue)
let task = session.dataTask(with: request) { (data, response, error) in
guard error == nil else {
print(error!)
return
}
// Success
if let statusCode = (response as? HTTPURLResponse)?.statusCode {
print("Success: \(statusCode)")
}
do {
let documentFolderURL = try FileManager.default.url(for: .downloadsDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let fileURL = documentFolderURL.appendingPathComponent(fileName)
try data!.write(to: fileURL)
DispatchQueue.main.async {
if FileManager.default.fileExists(atPath: fileURL.path) {
print("file present!") // Confirm that the file is here!
}
}
} catch {
print("error writing file \(error)")
}
}
observation = task.progress.observe(\.fractionCompleted) { progress, _ in
DispatchQueue.main.async(execute: {
self.globalScrollTitle.mainprogress = CGFloat(progress.fractionCompleted)
})
if progress.fractionCompleted == 1 {
completion()
}
}
task.resume()
}
}
Related Topics
Changing Vc Issue in Swift. How to Pass Data Between Views in Tab Bar Controller
How to Draw a Line Programmatically from a View Controller
Invalid Update: Invalid Number of Rows in Section 0
Scrollview Gesture Recognizer Eating All Touch Events
Combine Framework: How to Process Each Element of Array Asynchronously Before Proceeding
How to Create a Category in Xcode 6 or Higher
Uisearchbar Increases Navigation Bar Height in iOS 11
Duplicate Symbol Error in Objective-C Build
Check If a Uialertview Is Showing
iOS Uinavigationbar Button Remains Faded After Segue Back
Update Restkit 'Lcl_Rk.H' File Not Found in Rklog.H
Tutorial for Slcomposeviewcontroller Sharing
iOS 7 -- Navigationcontroller Is Setting the Contentinset and Contentoffset of My Uiscrollview
Counting the Number of Lines in a Uitextview, Lines Wrapped by Frame Size
Does H.264 Encoded Video with Bt.709 Matrix Include Any Gamma Adjustment
iOS 11 Navigation Bar Height Customizing