【问题标题】:Whole Session download progress Alamofire整个会话下载进度 Alamofire
【发布时间】:2016-03-19 17:33:34
【问题描述】:

Alamofire 被用于一次请求下载多个较大的文件。 我可以使用

分别查看每个文件的进度
Alamofire.request(.GET, imageURL).progress

但我想一次跟踪所有打开的会话的进度,但不知道该怎么做。 (假设我同时下载了 15 个文件) 我阅读了很多针对单个文件进度的教程,但对于整个会话没有。

是否可以使用 Alamofire 以这种方式跟踪进度?如果可以,如何?

【问题讨论】:

    标签: ios swift nsurlsession alamofire


    【解决方案1】:

    在 iOS9 中,您可以创建自己的 NSProgress 对象,并观察,例如 fractionCompleted。那你可以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)
            }
        }
    
    }
    

    如果您也需要 iOS 7/8 支持,可以致电 becomeCurrentWithPendingUnitCountresignCurrent

    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()
    }
    

    如果您使用的是 AFNetworking,它是相同的过程(即与上述相同的 viewDidLoadobserveValueForKeyPathdeinit 方法),但不是检索 Alamofire progress 属性,而是使用 @ 987654333@ 方法downloadProgressForTask 获取与NSURLSessionTask 关联的NSProgress。例如:

    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)
            }
        }
    }
    

    或者,如果使用下载任务:

    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()
        }
    }
    

    【讨论】:

    • 您好 Rob,您能举一个 AFNetworking 3.0 的多文件下载进度示例吗?
    • @Nuibb - 这确实应该是一个单独的问题,但我已经更新了我的答案,说明了 AFNetworking 示例......
    • @Rob,我尝试了你的方式,但得到了 NSInternalInconsistencyException。 here 你可以看到我的代码。谢谢。
    • @Nuibb - 一旦你像上面那样实现了observeValueForKeyPath,你的问题解决了吗?
    • 是的,那是缺少的链接。现在已经解决了。谢谢。
    猜你喜欢
    • 2015-07-20
    • 1970-01-01
    • 1970-01-01
    • 2015-12-25
    • 2016-02-07
    • 2014-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多