iOS: Save data in cachesDirectory or in documentDirectory?

Jasmine Elamblakatt
3 min readNov 21, 2020

Suppose there are some scenarios where you need to save some data in the App for some period of time.

Suppose you want to save a JSON file(i.e response received from server) in your app. The ideal way is to convert it to a model class and save it to CoreData.

But writing code for conversion and saving data in DB or CoreData may take some time and that's not imperative as you may just require to save that raw response for some time or for some days.

One way around is to save data in UserDefaults, but in such cases, as UserDefaults loads everything in memory when the app starts so bombarding UserDefaults with huge data is not a good approach.

In such scenarios, FileManger can be used to save data in the Cache folder or in the Directory folder.

Cache Folder(.cachesDirectory) is designed in such a way that it is for temporary storage, it won’t guarantee your data storage it may delete the data to free up disk space.

Directory Folder(.documentDirectory) saves the data till the App is deleted.

Let's check how to save response data in cachesDirectory

var userCacheURL: URL?
let userCacheQueue = OperationQueue()
if let cacheURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first {
userCacheURL = cacheURL.appendingPathComponent("users.json")
}
if (self.userCacheURL != nil) {
var result : [String: Any]? = nil
self
.userCacheQueue.addOperation() {
if let stream = InputStream(url: self.userCacheURL!) {
stream.open()
var users = (try? JSONSerialization.jsonObject(with: stream, options: [])) as? [String: Any]
stream.close()
if let users = users {
result = users
} else {
failedBlock(OverlayError.unexpected)
}
}
}

To retrieve or get the date from the cachesDirectory

if (self.userCacheURL != nil) {
var result : [String: Any]? = nil
self
.userCacheQueue.addOperation() {
if let stream = InputStream(url: self.userCacheURL!) {
stream.open()
var users = (try? JSONSerialization.jsonObject(with: stream, options: [])) as? [String: Any]
if let users = users {
result = users
}
stream.close()
}
}
}

I checked this technique on multiple devices and found that this way is not reliable and data gets deleted soon once multiple app is active in the background or there is low memory condition.

So the reliable way to save data for any period of time is to use documentDirectory of FileManager class.

Check the below code to save data in documentDirectory

let text = String(data: jsonData, encoding: .utf8)
let
file = "test.txt"
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {let fileURL = dir.appendingPathComponent(file)do {
try text.write(to: fileURL, atomically: false, encoding: .utf8)
}
catch {}
}

Code to read Data from the directory

func readFile(fileName: String) -> String{  let file = "\(fileName).txt"if let dir = FileManager.default.urls(for: .documentDirectory,     in: .userDomainMask).first {let fileURL = dir.appendingPathComponent(file)
do {
let text = try String(contentsOf: fileURL, encoding: .utf8)
return text
}
catch {
return ""
}
}
return ""
}

To delete the file from DocumentDirectory

let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
do {
let fileURLs = try FileManager.default.contentsOfDirectory(at: documentsUrl,includingPropertiesForKeys: nil,options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants])
for fileURL in fileURLs {
if fileURL.pathExtension == “txt” {
try FileManager.default.removeItem(at: fileURL)
}
}
} catch { print(error) }

Now for saving images in the cache for a longer time the best library after checking few image loading libraries in iOS the one which was working superbly for me was the SDWebImage library.

SDWebImage library is the optimal one to cache images for many days.

https://github.com/SDWebImage/SDWebImage

HaPpY CoDiNg…..

--

--