Swift. Как отследить процесс загрузки downloadTask? (с использованием completionHandler)

При создании downloadTask мне требуется completionHandler для обработки некоторых данных. В документации сказано: "You should pass a nil completion handler only when creating tasks in sessions whose delegates include a urlSession(_:downloadTask:didFinishDownloadingTo:) method." То есть, при использовании completionHandler методы делегата URLSessionDownloadDelegate по отслеживанию процесса загрузки не работают. Есть ли другой способ отследить прогресс?


Ответы (1 шт):

Автор решения: schmidt9

Можно еще отследить используя свойство задания progress и KVO начиная с iOS 11 (см оригинальный ответ), progress.fractionCompleted в примере будет изменяться в диапазоне от 0 до 1

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet var imageView: UIImageView!
    
    var image: UIImage?
    var progressKVOContext: UnsafeMutableRawPointer?

    override func viewDidLoad() {
        super.viewDidLoad()
        testDownloadTask()
    }
    
    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 {
                    print("completed \(progress.fractionCompleted)")
                }
                
            case "isCancelled":
                print(keyPath)
            default:
                break
            }
        } else {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        }
    }
    
    func testDownloadTask() {
        let session = URLSession.shared
        let url = URL(string: "https://upload.wikimedia.org/wikipedia/commons/d/d4/Deerfire_high_res.jpg")!

        let task = session.downloadTask(with: url) { [weak self] url, response, error in
            if let error = error {
                print(error)
                return
            }

            print("saved using callback", url)

            // You must move this file or open it for reading before your completion handler returns.
            // Otherwise, the file is deleted, and the data is lost.
            self?.image = UIImage(contentsOfFile: url!.path)

            DispatchQueue.main.async {
                self?.imageView.image = self?.image
            }
        }
        
        task.progress.addObserver(self, forKeyPath: "fractionCompleted", options: .new, context: &self.progressKVOContext)
        task.resume()
    }

}
→ Ссылка