如何在Swift中防止我的HTTP Get请求被缓存?

7
我遇到了一个奇怪的bug,它突然出现了。我快要完成我的应用程序并进行测试时,我发现数据没有被更新。数据库已经更新了,我可以直接访问URL,并正确地从服务器返回数据,但是当我在Swift中打印数据时,它没有改变。
大多数情况下,重新运行应用程序后数据会更改。
我正在使用Alamofire,但我也尝试了另外两种方法:
let url = NSURL(string: "http://www.stackoverflow.com")
let request = NSURLRequest(URL: url!)

NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {(response, data, error) in
    println(NSString(data: data, encoding: NSUTF8StringEncoding))
}

并且。
let url = NSURL(string: "http://www.stackoverflow.com")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
    println(NSString(data: data, encoding: NSUTF8StringEncoding))
}

task.resume()

所有三个都输出相同的数据。

我猜这是 Swift 中的缓存问题,但我没有设置任何东西告诉 Swift 缓存数据,而且它在过去几周一直正常工作。

我今天唯一做的事情就是为我的项目创建一个 Git 仓库。

有人知道可能是什么原因吗?


*编辑:

使用 Abhi Beckert 的答案,我尝试了以下操作:

符合代理 NSURLConnectionDelegate

添加:

func connection(connection: NSURLConnection, willCacheResponse cachedResponse: NSCachedURLResponse) -> NSCachedURLResponse?
{
  return nil // never cache anything. ever.
}

然后进行调用:

let url:NSURL! = NSURL(string: "http://coffee.datausadev.com/api/getCoffeeBrands")
let request = NSURLRequest(URL: url, cachePolicy: .ReloadIgnoringLocalCacheData, timeoutInterval: 60)

NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {(response, data, error) in
    println(NSString(data: data, encoding: NSUTF8StringEncoding))
}

这种方法仍然没有生效。

3个回答

2
您需要将控制器对象设置为NSURLConnection的代理:
let request = NSURLRequest(URL: requestURL, cachePolicy: .ReloadIgnoringLocalCacheData, timeoutInterval: 60)
self.currentConnection = NSURLConnection(request: request, delegate: self)

这也需要让自身符合数据源:
class MyController: NSURLConnectionDataDelegate {

使用相关的委托方法禁用缓存:

func connection(connection: NSURLConnection, willCacheResponse cachedResponse: NSCachedURLResponse) -> NSCachedURLResponse?
{
  return nil // never cache anything. ever.
}

.ReloadIgnoringLocalCacheData选项会禁用读取缓存,willCacheResponse代理方法则禁用写入缓存。你需要同时使用这两个选项。

不幸的是,这意味着你不能使用sendAsynchronousRequest便捷方法和阻塞回调 - 相反,你将不得不使用NSURLConnectionDataDelegate中的代理方法来处理响应。基本上,你需要创建一个NSMutableData对象,并在连接传入数据时将其附加到该对象上,直到连接告诉你请求已经完成或失败为止 — 然后你就可以对数据进行处理了。

据我所知,使用sendAsynchronousRequest时无法完全禁用缓存。你可能希望创建一个包装类来整理你的代码。


1
我非常确定,在使用iOS7中引入的NSUrlSession时,可以通过使用临时配置并在下载完成后使会话失效(根据苹果文档,这将清除缓存)来实现上述操作。 - joakim
我得到了“类没有名为currentConnection的成员”的错误信息。我编辑了我的帖子以展示我尝试过的内容,但仍然无法解决。 - Kolby
@Kolby 你需要在你的类上拥有一个实例变量来存储 currentConnection。阅读一下苹果关于如何使用 NSURLConnection 的文档,他们在那里提供了所有的代码 - 我只发布了与缓存相关的部分。 - Abhi Beckert

1
我尝试了一切,但没有帮助。这个解决方案对我有用(Swift 3
每次HttpResponse后,我调用了destroyCache()函数。
 public static func destroyCache() {
        let fileManager = FileManager.default
        let documentsUrl =  fileManager.urls(for: FileManager.SearchPathDirectory.cachesDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).first! as NSURL
        let documentsPath = documentsUrl.path
        let bundleIdentifier = Bundle.main.bundleIdentifier! as String
        do {
            if let documentPath = documentsPath
            {
                let fileNames = try fileManager.contentsOfDirectory(atPath: "\(documentPath)/\(bundleIdentifier)")
                for fileName in fileNames {
                    let filePathName = "\(documentPath)/\(bundleIdentifier)/\(fileName)"
                    try fileManager.removeItem(atPath: filePathName)
                }
            }

        } catch {
            print("Could not clear: \(error)")
        }
    }

1
这不是Swift错误。
在幕后,NSURLSession根据支持它的配置对象遵循特定策略。
默认配置(通过sharedSession单例使用的那个)使用“当前设置的全局NSURLCache、NSHTTPCookieStorage和NSURLCredentialStorage对象,并基于默认配置”,详见NSUrlSession参考
你有以下选择:
1. 使用“短暂”的配置,几乎不缓存任何内容(类似于私人浏览模式)。 2. 自己设置配置并将缓存和其他策略设置为适合你的需要。
别忘了考虑服务器的策略。要么查询文档,要么根据响应请求返回的http头做出最佳决策。 编辑:我刚刚注意到你最初使用了Alamofire。它和Objective-C中的AF所做的只是提供一种方便、更高级别的方式,来完成iOS7之前你使用NSURLSession和NSURLConnection所做的相同事情。它们都必须让你自定义缓存,请参考它们的文档。

是的,我真的很想找到一种使用Alamofire的方法。我已经多次阅读了他们的文档,唯一提到缓存的事情是:“缓存由NSURLCache在系统框架级别上处理。” - Kolby
你确定他们没有提到过自己玩缓存的事情吗?我知道 AFNetworking,Alamofire 的 Objective-C 兄弟可以让你这样做,而且它是由同一批人编写的。这是一个开源项目,你总是可以深入挖掘并自己添加 :) - joakim
这就是我在周五发布之前开始做的事情。这是我的第一个Swift应用程序,所以我还在学习中。您介意提供短暂配置的代码吗? - Kolby

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接