在对同一个远程 url 已编辑

问题描述

我使用 URLSessionDataTask 显示图像,并使用 URLSessionDownloadTask 在我的应用中下载图像。我还需要观察下载进度,所以我在 ProgressfractionCompleted 使用 KVO。

问题是 fractionCompleted 值只有 0.051.0。我认为这个问题发生在使用相同的远程 url 时。因为当我不使用 URLSessionDataTask 时(虽然我无法显示图像),我会得到正确的进度更新。

为什么会这样?有参考吗?

已编辑

首先,我不想使用 URLSession 委托来获取进度。我正在使用两个 VC(第一个RemoteGridViewController,使用 URLSessionDataTask 显示图像,第二个是 MediaViewerController)。 MediaViewerController 委托第一个 VC 下载相机胶卷上的图像。我知道我可以使用 URLSession 委托方法通过使用 NotificationCenter 或类似的东西来通知进度,但我不想要。这种方式在 VC 之间形成了强耦合(?)(我猜...)

其次,RemoteGridViewController 使用 URLSession 显示 URLSessionDataTask 的图像并缓存它。

guard let url = URL(string: url) else {
    completionHandler(.failure(NetworkManagerError.urlError))
    return
}

var req = URLRequest(url: url)
req.cachePolicy = .returnCacheDataElseLoad

if let cachedResponse = sharedCache?.cachedResponse(for: req) {
    completionHandler(.success(cachedResponse.data))
} else {
    sessionDataTask = session.dataTask(with: req) { [weak self] (data,response,error) in
        if let error = error {
            completionHandler(.failure(error))
            print(error.localizedDescription)
            return
        }
        
        guard let response = response as? HTTPURLResponse,let data = data else {
            completionHandler(.failure(NetworkManagerError.dataError))
            return
        }
        self?.sharedCache?.storeCachedResponse(CachedURLResponse(response: response,data: data),for: req)
        completionHandler(.success(data))
    }
    
    sessionDataTask?.resume()
}

第三,MediaViewerController调用MediaViewerDelegate方法,即downloadImage(itemAt:for:)下载图片

extension RemoteGridViewController: MediaViewerDelegate {
    func downloadImage(itemAt indexPath: IndexPath,for mediaViewer: MediaViewerController) {
        let data = unsplashData[indexPath.item]
        let urlString = data.regular
        
        guard let url = URL(string: urlString) else { return }
        
        mediaViewer.presentProgressView()

        networkManager.downloadTaskForImage(with: url,progressHandler: mediaViewer.observe(_:)) { result in
            switch result {
            case .success(let image):
                dispatchQueue.main.async {
                    mediaViewer.toastView(with: true)
                }
                UIImageWritetoSavedPhotosAlbum(image,nil,nil)
            case .failure(let error):
                dispatchQueue.main.async {
                    mediaViewer.toastView(with: false)
                }
                print(error.localizedDescription)
            }
        }
    }
}

class NetworkManager {
    private let session: URLSession!
    private var sessionDownloadTask: URLSessionDownloadTask?
    
    func downloadTaskForImage(with url: URL,progressHandler: (Progress?) -> (),completionHandler: @escaping (Result<UIImage,Error>) -> ()) {
        sessionDownloadTask = session.downloadTask(with: url) { (location,error) in
            if let error = error {
                completionHandler(.failure(error))
                return
            }
            
            guard let response = response as? HTTPURLResponse,(200...299).contains(response.statusCode) else {
                completionHandler(.failure(NetworkManagerError.responseError))
                return
            }
            
            guard let location = location else {
                completionHandler(.failure(NetworkManagerError.urlError))
                return
            }
            
            do {
                let data = try Data(contentsOf: location)
                if let image = UIImage(data: data) {
                    completionHandler(.success(image))
                } else {
                    completionHandler(.failure(NetworkManagerError.dataError))
                }
            } catch let error {
                completionHandler(.failure(error))
            }
        }
        
        progressHandler(sessionDownloadTask?.progress)
        sessionDownloadTask?.resume()
    }
}

解决方法

您可以跟踪下载的字节数到总预期字节数以跟踪下载图像的进度。

使用以下委托方法:

URLSession(_:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:)

以及以下代码段:

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)
        
        //Your code to download and save image to camera role
    }
}

我希望这可以解决您的查询以检查下载的确切进度。