Greetings, traveler!
iOS File System is a powerful tool for storing data. However, it is not the only option since Apple offers other tools for different scenarios.
Note
By the way, if you want to read more about these options, you can do so here.
If your app frequently uses the File System, you may want to create a universal tool to perform CRUD operations. So, let’s do this.
Create a class FileSystemManager
.
final class FileSystemManager {
}
Now, let’s enhance it.
File path
First, we need to specify the URL to perform any operation. To do this, we need to know three parameters.
- Key — a string path component.
- Directory — a directory which will be used.
- Domain mask — domain constants specifying base locations to use when you search for significant directories. We will use the user’s home directory by default.
Note
By the way, if you want to read more about FileManager directories, you can check out this article.
Now, let’s create a private method. This method will be throwable and return a URL
. We will specify the document directory, append our custom path component, and return this value.
private func filePath(
key: String,
directory: FileManager.SearchPathDirectory,
domainMask: FileManager.SearchPathDomainMask
) throws -> URL {
let documentDirectory = try FileManager.default.url(
for: directory,
in: domainMask,
appropriateFor: nil,
create: false
)
return documentDirectory.appendingPathComponent(key)
}
Save
Now, we can perform CRUD operations. Let’s start with saving. We can only use objects that conform to the Codable
protocol, so we can use a generic method. We will use the same parameters but with an additional one — the first parameter will be the data to save.
We will create JSON
data with the JSONEncoder
and write it using the desired file path.
func save<T: Codable>(
_ data: T,
key: String,
directory: FileManager.SearchPathDirectory,
domainMask: FileManager.SearchPathDomainMask = .userDomainMask
) throws {
let filePath = try filePath(
key: key,
directory: directory,
domainMask: domainMask
)
let jsonData = try JSONEncoder().encode(data)
try jsonData.write(to: filePath)
}
Retrieve
To retrieve an object, we will use our filePath
method once again. After retrieving the contents of the provided file path, we can use JSONDecoder
to decode it and return its value.
func retrieve<T: Codable>(
_ type: T.Type,
key: String,
directory: FileManager.SearchPathDirectory,
domainMask: FileManager.SearchPathDomainMask = .userDomainMask
) throws -> T {
let filePath = try filePath(
key: key,
directory: directory,
domainMask: domainMask
)
let jsonData = try Data(contentsOf: filePath)
return try JSONDecoder().decode(T.self, from: jsonData)
}
Delete
This is the most straightforward method. After the file path is specified, we just need to call the FileManager
removeItem
method.
func delete(
key: String,
directory: FileManager.SearchPathDirectory,
domainMask: FileManager.SearchPathDomainMask = .userDomainMask
) throws {
let filePath = try filePath(
key: key,
directory: directory,
domainMask: domainMask
)
try FileManager().removeItem(at: filePath)
}
Examples of usage
That’s it! Now, we have a universal tool for CRUD operations. Let’s try it out.
let manager = FileSystemManager()
// Save
try? manager.save("Test", key: "test", directory: .cachesDirectory)
// Retrieve
let object = try? manager.retrieve(
String.self,
key: "test",
directory: .cachesDirectory
)
print(object) // Test
// Delete
try? manager.delete(key: "test", directory: .cachesDirectory)
Conclusion
You can enhance this tool of your choice. Anyway, if you want to check out the source code or use this tool as a framework in your project, you can do so on my GitHub.
If you enjoyed this article, please feel free to follow me on my social media: