URLCache(iOS). storeCachedResponse异步工作.如何赶上完成? [英] URLCache (iOS). storeCachedResponse works asynchronously. How to catch the completion?

查看:84
本文介绍了URLCache(iOS). storeCachedResponse异步工作.如何赶上完成?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

刚刚发现函数storeCachedResponse(_ cachedResponse:CachedURLResponse,对于请求:URLRequest)是异步工作的.也就是说,执行后不会立即返回结果.我没有在官方文档中找到对此的描述. 参见示例:

Just discovered that the function storeCachedResponse(_ cachedResponse: CachedURLResponse, for request: URLRequest) works asynchronously. That is, the result is not returned immediately after execution. I did not find a description of this in the official documentation. See example:

cache = URLCache(memoryCapacity: 0, diskCapacity: 100 * 1024 * 1024, diskPath: "myCache")
let config = URLSessionConfiguration.default
config.requestCachePolicy = .returnCacheDataElseLoad
config.urlCache = cache
let session = URLSession(configuration: config)
session.dataTask(with: request, completionHandler: {[unowned self]
    (data, response, error) in

    if let data = data, let response = response, ((response as HTTPURLResponse)?.statusCode ?? 500) < 300 {
        let cachedData = CachedURLResponse(response: response, data: data)                                            
        self.cache.storeCachedResponse(cachedData, for: request)
        let testCachedData = self.cache.cachedResponse(for: request)
    }
}

理论上,testCachedData必须包含缓存的响应.但是它实际上包含的内容:

Theoretically testCachedData must contain cached response. But what it actually contains:

testCachedData?.response.url // Ok
testCachedData?.isEmpty // false
testCachedData?.data // 0 bytes!!!

尽管testCachedData?.data表示它包含0个字节,但我们可以将此数据写入文件,并且该文件将包含实际数据,而不是0.如果我们深入本地缓存目录(〜/Library/Caches/myApp/MyCache)在cachedResponse调用后立即在断点处暂停时,我们可以看到带有缓存文件(fsCachedData)的文件夹尚不存在. 现在让我们在storeCachedResponse和cachedResponse之间插入延迟:

Although testCachedData?.data says it contains 0 bytes, we can write this data to a file, and this file will contain real data, not 0. If we deep into local cache directory (~/Library/Caches/myApp/MyCache) when pausing at breakpoint right after cachedResponse call, we can see that folder with cached files (fsCachedData) doesn't exist yet. Now let's insert delay between storeCachedResponse and cachedResponse:

cache = URLCache(memoryCapacity: 0, diskCapacity: 100 * 1024 * 1024, diskPath: "myCache")
let config = URLSessionConfiguration.default
config.requestCachePolicy = .returnCacheDataElseLoad
config.urlCache = cache
let session = URLSession(configuration: config)
session.dataTask(with: request, completionHandler: {[unowned self]
    (data, response, error) in

    if let data = data, let response = response, ((response as HTTPURLResponse)?.statusCode ?? 500) < 300 {
        let cachedData = CachedURLResponse(response: response, data: data)                                            
        self.cache.storeCachedResponse(cachedData, for: request)
        delay(5) // JUST 5 SEC DELAY
        let testCachedData = self.cache.cachedResponse(for: request)
    }
}

现在:

testCachedData?.response.url // Ok
testCachedData?.isEmpty // false
testCachedData?.data // contains bytes

因此,在延迟5秒后,我们看到缓存文件文件夹(fsCachedData)存在并且包含缓存文件(例如D8A30D21-C8F1-4FCA-967E-F6B440998173).

So, after 5 sec delay we see that cached files folder (fsCachedData) exists and contains cached file (e.g. D8A30D21-C8F1-4FCA-967E-F6B440998173).

重点是如何捕获storeCachedResponse的完成?

The point is how to catch the completion of storeCachedResponse?

创建缓存文件后,我将立即使用它们.而且,我将直接处理缓存的文件,这不是设置延迟的最佳解决方案.

I'm going to use cached files right after they are created. Moreover, I'm going to handle cached files directly, and it's not the best solution to set delay.

推荐答案

实际上我不明白为什么您在缓存后立即调用缓存的数据!我认为您应该在请求会话会话url之前调用缓存的数据(如果存在),返回缓存的数据,否则从头开始请求.

Actually I couldn't understand why you calling cached data immediately after caching!? In my opinion you should call cached data before requesting url with session if data is exist return cached data else request from the scratch.

例如:

private let allowedDiskSize = 100 * 1024 * 1024
private lazy var cache: URLCache = {
    return URLCache(memoryCapacity: 0, diskCapacity: allowedDiskSize, diskPath: "gifCache")
}()

typealias DownloadCompletionHandler = (Result<Data,Error>) -> ()

private func createAndRetrieveURLSession() -> URLSession {
    let sessionConfiguration = URLSessionConfiguration.default
    sessionConfiguration.requestCachePolicy = .returnCacheDataElseLoad
    sessionConfiguration.urlCache = cache
    return URLSession(configuration: sessionConfiguration)
}

private func downloadContent(fromUrlString: String, completionHandler: @escaping DownloadCompletionHandler) {

    guard let downloadUrl = URL(string: fromUrlString) else { return }
    let urlRequest = URLRequest(url: downloadUrl)
    // First try to fetching cached data if exist
    if let cachedData = self.cache.cachedResponse(for: urlRequest) {
        print("Cached data in bytes:", cachedData.data)
        completionHandler(.success(cachedData.data))

    } else {
        // No cached data, download content than cache the data
        createAndRetrieveURLSession().dataTask(with: urlRequest) { (data, response, error) in

            if let error = error {
                completionHandler(.failure(error))
            } else {

                let cachedData = CachedURLResponse(response: response!, data: data!)
                self.cache.storeCachedResponse(cachedData, for: urlRequest)

                completionHandler(.success(data!))
            }
        }.resume()
    }
}

和用法:

self.downloadContent(fromUrlString: ANY_URL, completionHandler: { (result) in

            switch result {
            case .success(let yourData):
                // handle data

            case .failure(let error):
                debugPrint(error.localizedDescription)
            }
 })

第一次它将从Web上获取数据,并且在第二次请求时它将立即返回缓存的数据.

First time it will fetch data from the web and in second request it will return cached data immediately.

这篇关于URLCache(iOS). storeCachedResponse异步工作.如何赶上完成?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆