Alamofire is being used to download multiple larger files at one request. I am able to make progress be seen for each file separately using
Alamofire.request(.GET, imageURL).progress
But I would like to track the progress of all open sessions at once and do not know how to do that. (lets say I have 15 files downloading simultaneously) I read a lot of tutorials that address single file progress but for whole session none.
Is it possible to track progress that way with Alamofire and if it is, how?
In iOS9, you can create your own NSProgress
object, and observe, for example, fractionCompleted
. Then you can addChild
:
private var observerContext = 0
class ViewController: UIViewController {
private var progress: NSProgress!
override func viewDidLoad() {
super.viewDidLoad()
progress = NSProgress()
progress.addObserver(self, forKeyPath: "fractionCompleted", options: .New, context: &observerContext)
downloadFiles()
}
deinit {
progress?.removeObserver(self, forKeyPath: "fractionCompleted")
}
private func downloadFiles() {
let filenames = ["as17-134-20380.jpg", "as17-140-21497.jpg", "as17-148-22727.jpg"]
let baseURL = NSURL(string: "http://example.com/path")!
progress.totalUnitCount = Int64(filenames.count)
progress.completedUnitCount = 0
for filename in filenames {
let url = baseURL.URLByAppendingPathComponent(filename)
let childProgress = Alamofire.request(.GET, url.absoluteString)
.response() { request, response, data, error in
// process response
}
.progress
progress.addChild(childProgress, withPendingUnitCount: 1)
}
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if context == &observerContext {
if keyPath == "fractionCompleted" {
let percent = change![NSKeyValueChangeNewKey] as! Double
print("\(percent)")
}
} else {
super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
}
}
}
If you need support for iOS 7/8, too, you can call becomeCurrentWithPendingUnitCount
and resignCurrent
:
for filename in filenames {
let url = baseURL.URLByAppendingPathComponent(filename)
progress.becomeCurrentWithPendingUnitCount(1)
Alamofire.request(.GET, url.absoluteString)
.response() { request, response, data, error in
// process response
}
progress.resignCurrent()
}
If you are using AFNetworking, it's the same process (i.e. the same viewDidLoad
, observeValueForKeyPath
, and deinit
methods as above), but rather than retrieving the Alamofire progress
property, you instead use the AFHTTPSessionManager
method downloadProgressForTask
to get the NSProgress
associated with the NSURLSessionTask
. For example:
private func getFiles() {
let filenames = ["as17-134-20380.jpg", "as17-140-21497.jpg", "as17-148-22727.jpg"]
let manager = AFHTTPSessionManager()
manager.responseSerializer = AFHTTPResponseSerializer()
let baseURL = NSURL(string: "http://example.com/path")!
progress.totalUnitCount = Int64(filenames.count)
progress.completedUnitCount = 0
for filename in filenames {
let url = baseURL.URLByAppendingPathComponent(filename)
let task = manager.GET(url.absoluteString, parameters: nil, progress: nil, success: { task, responseObject in
// do something with responseObject
print(url.lastPathComponent! + " succeeded")
}, failure: { task, error in
// do something with error
print(error)
})
if let downloadTask = task, let childProgress = manager.downloadProgressForTask(downloadTask) {
progress.addChild(childProgress, withPendingUnitCount: 1)
}
}
}
Or, if using download tasks:
private func downloadFiles() {
let filenames = ["as17-134-20380.jpg", "as17-140-21497.jpg", "as17-148-22727.jpg"]
let manager = AFHTTPSessionManager()
let baseURL = NSURL(string: "http://example.com/path")!
progress.totalUnitCount = Int64(filenames.count)
progress.completedUnitCount = 0
let documents = try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
for filename in filenames {
let url = baseURL.URLByAppendingPathComponent(filename)
let task = manager.downloadTaskWithRequest(NSURLRequest(URL: url), progress: nil, destination: { (temporaryURL, response) -> NSURL in
return documents.URLByAppendingPathComponent(url.lastPathComponent!)
}, completionHandler: { response, url, error in
guard error == nil else {
print(error)
return
}
if let name = url?.lastPathComponent {
print("\(name) succeeded")
}
})
if let childProgress = manager.downloadProgressForTask(task) {
progress.addChild(childProgress, withPendingUnitCount: 1)
}
task.resume()
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With