The Airsource Blog

Caching broken on iOS 8 - 1/3

Part 2, with source code and detailed results, is now available.

The roundup for the released version of 8.1 is available in Part 3.

Apple have already experienced one PR disaster with the iOS 8.0.1 release which broke cell phone operation for some users. They may be on their way to another problem - less serious this time, but still significant. NSURLCache has been around since iOS 2, and using a disk cache since iOS 5 (really using it, not just saying that it did). As you'd expect, this means that if you open up an NSURLConnection, it will cache responses, take account of Cache-control headers, and purge old cached responses as needed to keep the cache size within specified limits.

Unfortunately, this is broken on iOS 8.0. There are several complaints circulating around about NSURLCache not working properly with NSURLSession or UIWebView. However, that is not the topic of this article. It does work with NSURLConnection - but it never purges the cache.

Yes, that's right - the cache size grows indefinitely. Moreover, the reported cache size provided by currentDiskUsage is way too low.

I ran a simple test test suite presented in Part 2 on iOS 7.1.2, 8.0, 8.0.2, and 8.1 beta. My test used a single NSURLConnection, set up to fetch a PNG image from a locally hosted server. The server did not specify any Cache-control headers. I initialised an NSURLCache with:

    // Set up a 1MB RAM, 10MB disk cache in the default location (Library/Caches/com.whatever.myapp)
    NSURLCache *cache = [[NSURLCache alloc] initWithMemoryCapacity:1000000 diskCapacity:10000000 diskPath:nil];
    [NSURLCache setSharedURLCache:cache];

I then fetched an image, with the URL used to fetch the image changing each time so that every response would be cached. This ensured I would rapidly reach the 10MB disk limit. I also continually polled the number of files in the fsCachedData subdirectory of the cache, in order to determine when the operating system started deleting files.

iOS 7.1.2 reported a plausible disk usage for the cache at each stage. It was slightly incorrect (it excluded the write-ahead log file) but at least it was consistent with the amount of data stored on the file system. Once the disk capacity was reached, the operating system started deleting files from fsCachedData. In short, the cache worked properly.

However on iOS 8.0, and 8.0.2, the cache size grew indefinitely. The reported disk usage of the cache as provided by the property currentDiskCapacity was far below the true usage, as verified both by using iExplorer, checking the files in fsCachedData, and viewing the usage report in the Settings app. The operating system never deleted any files. This corresponds with the bug report provided by one of the users of our Early Edition 2 application who complained that the app was using over a gigabyte of store on iOS 8!

It is clear that Apple changed some key aspects of caching on iOS 8 - just take a look at the API diffs for iOS 7.1 to 8.0. NSURLCache gained some extra methods in the category NSURLSessionTaskAdditions, which rather suggests that the issues people have been experiencing with NSURLSessions are related to this change. I checked the API diffs for iOS 8.0 to 8.1 but there were no relevant changes.

1However, on iOS 8.1 (both beta 1 and beta 2) the cache does appear to be working properly, with the exception of deleting individual cache items - see Part 2. I am, however, extremely disappointed to see that the 2Release Notes make no mention of this issue, and I can only speculate as to why Apple might want to not draw attention to it.

The consequences of unlimited cache growth are, of course, that the device will inevitably run out of space. Since most apps do not provide a facility to clear the cache (an omission that Airsource have also made - I can assure our users that this oversight will not be repeated), this means that the only way to free up space is to backup the application data, uninstall it, and then reinstall it. I thought I had left that behind when I moved from a PC to a Mac.

The longer Apple waits before releasing iOS 8.1, the less space users will have on their devices. iOS 8 has already experienced reduced install rates due to its storage requirements. There is a very real risk that some (many?) users will be unable to update their devices OTA without uninstalling apps first - and the apps they will have to uninstall will, by the nature of this bug, be the apps that they most frequently use. Not impressed, Tim, not impressed.

Part 2, with source code and detailed results, is now available.

  1. Apple used to heavily restrict what developers could say about beta releases of iOS (i.e. you weren't allowed to say anything). However, this recently changed, and technical information is fine.  

  2. The Release Notes for the first beta are available here, cunningly hidden under an 8.0 URL.