首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >URLCache (iOS)。storeCachedResponse异步工作。怎样才能赶上完工?

URLCache (iOS)。storeCachedResponse异步工作。怎样才能赶上完工?
EN

Stack Overflow用户
提问于 2018-12-05 02:52:37
回答 1查看 5.7K关注 0票数 5

刚刚发现函数storeCachedResponse(_ cachedResponse: CachedURLResponse,for request: URLRequest)异步工作。也就是说,执行后不会立即返回结果。我在正式文件中没有找到这方面的说明。见示例:

代码语言:javascript
复制
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必须包含缓存的响应。但它真正包含的是:

代码语言:javascript
复制
testCachedData?.response.url // Ok
testCachedData?.isEmpty // false
testCachedData?.data // 0 bytes!!!

虽然testCachedData?.data说它包含0字节,但是我们可以将这个数据写入一个文件,并且这个文件将包含真实的数据,而不是0。如果我们深入到本地缓存目录(~/Library/ cache /myApp/MyCache),在cachedResponse调用后的断点暂停,我们可以看到缓存文件(fsCachedData)的文件夹还不存在。现在让我们在storeCachedResponse和cachedResponse之间插入延迟:

代码语言:javascript
复制
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)
    }
}

现在:

代码语言:javascript
复制
testCachedData?.response.url // Ok
testCachedData?.isEmpty // false
testCachedData?.data // contains bytes

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

关键是如何捕捉storeCachedResponse的完成?

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-04-29 19:36:53

实际上,我不明白为什么在缓存之后立即调用缓存的数据!?在我看来,您应该在使用会话请求url之前调用缓存的数据,如果存在数据,则从零开始返回缓存的数据或其他请求。

例如:

代码语言:javascript
复制
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()
    }
}

和用法:

代码语言:javascript
复制
self.downloadContent(fromUrlString: ANY_URL, completionHandler: { (result) in

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

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

第一次它将从web获取数据,在第二次请求中,它将立即返回缓存的数据。

票数 14
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53624466

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档