removeCachedResponseForRequest doesn't work in IOS 9?

Hi,

I tried to use removeCachedResponseForRequest but it doesn't remove anything. Apparently is broken since IOS 8.


NSURLCache.sharedURLCache().removeCachedResponseForRequest(request)


I checked and the "request" is in the array of requests inside NSURLCache.sharedURLCache()


Any idea or work around to fix it?

Thank you for your help.

Accepted Reply

I checked and the "request" is in the array of requests inside

NSURLCache.sharedURLCache()

I don’t understand this comment. NSURLCache does not publish an “array of requests”, at least not via any public API.

However, the bug you’re seeing is real. It was reported as fixed in iOS 10 (r. 22788696) but that fix isn’t working for me. I’ve filed a new bug about this (r. 28752537).

There’s a couple of ways you can work around this:

  • You can dump the entire cache using

    removeAllCachedResponses()
    .
  • You can set the cache policy on any new request for this resource to

    .reloadIgnoringLocalCacheData
    , causing that request to ignore the cached value.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

I checked and the "request" is in the array of requests inside

NSURLCache.sharedURLCache()

I don’t understand this comment. NSURLCache does not publish an “array of requests”, at least not via any public API.

However, the bug you’re seeing is real. It was reported as fixed in iOS 10 (r. 22788696) but that fix isn’t working for me. I’ve filed a new bug about this (r. 28752537).

There’s a couple of ways you can work around this:

  • You can dump the entire cache using

    removeAllCachedResponses()
    .
  • You can set the cache policy on any new request for this resource to

    .reloadIgnoringLocalCacheData
    , causing that request to ignore the cached value.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
I don’t understand this comment. NSURLCache does not publish an “array of requests”, at least not via any public API.


I explain wrong. I use NSURLCache.sharedURLCache().cachedResponseForRequest(request) to know if the response exists in the NSURLCache.sharedURLCache().


Mmmm i wil try the second way.


Thank eskimo 🙂

I am also facing same issue in all versions: iOS 9, 10 and 11. Is still fix not provided for this?

I just want to remove one item from cache but as this method is not working I need to dump entire cache.

Is still fix not provided for this?

I just had a look at the bug I filed about this (r. 28752537) and it’s still unresolved.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
Hi eskimo,

I can’t find your bug report anymore but I still have this issue. Is this bug fixed?

Is this bug fixed?

The bug I filed about this (r. 28752537) was fixed in iOS 13. I personally verified that fix at the time, but there’s always the possibility that the patch came unstuck somewhere.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Hi Eskimo,

Thanks for your response. I have made a small Playground example to illustrate the problem I have. In the code below when I run it I never reach the "Made it" print line. It always fails somewhere inside the loop. It always fails on the remove never on the store. Atleast in the 20-30 times I ran it. This is ofcourse not something I do in production code but this way I get to see the behaviour more clear.

Code Block swift
import Foundation
if #available(iOS 14, *) {
  print("iOS 14 available")
}
let url = URL(string: "https://apple.com")!
var request = URLRequest(url: url)
request.httpBody = "test".data(using: .utf8)!
let httpResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil)!
let cachedURLResponse = Foundation.CachedURLResponse(response: httpResponse, data: request.httpBody!)
let cache = URLCache.shared
cache.removeAllCachedResponses()
assert(cache.cachedResponse(for: request) == nil, "Remove all should start clean")
for i in 0..<500 {
  cache.storeCachedResponse(cachedURLResponse, for: request)
  assert(cache.cachedResponse(for: request) != nil, "[\(i)] Request should be found inside the cache")
  cache.removeCachedResponse(for: request)
  assert(cache.cachedResponse(for: request) == nil, "[\(i)] Request should be removed")
  cache.storeCachedResponse(cachedURLResponse, for: request)
  assert(cache.cachedResponse(for: request) != nil, "[\(i)] Request should be found inside the cache")
}
print("Made it!")

My experience is that the cache tends to run async, so if you delete an item and then immediately request an item you get back the original item. You only get back nil once the delete has run to completion.

You can see this in action with the code below, which doesn’t hit any of thes asserts.

As to whether the cache should work this way, that’s a more subtle question and you should feel free to make your case in a bug report.

Please post your bug number, just for the record.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"



Code Block
func testAsync() {
print("start")
let url = URL(string: "https://apple.com")!
request = URLRequest(url: url)
self.request.httpBody = "test".data(using: .utf8)!
let httpResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil)!
self.cachedURLResponse = Foundation.CachedURLResponse(response: httpResponse, data: request.httpBody!)
let cache = URLCache.shared
cache.removeAllCachedResponses()
assert(cache.cachedResponse(for: request) == nil, "Remove all should start clean")
self.count = 0
step1()
}
var request: URLRequest!
var cachedURLResponse: CachedURLResponse!
var count: Int = 0
func step1() {
let cache = URLCache.shared
assert(cache.cachedResponse(for: request) == nil, "[\(count)] Request should be removed")
cache.storeCachedResponse(cachedURLResponse, for: request)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
self.step2()
}
}
func step2() {
let cache = URLCache.shared
assert(cache.cachedResponse(for: request) != nil, "[\(count)] Request should be found inside the cache")
cache.removeCachedResponse(for: request)
count += 1
if count < 500 {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
self.step1()
}
} else {
print("done")
}
}