Skip to content

Instantly share code, notes, and snippets.

@khanlou
Last active June 6, 2020 19:40
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save khanlou/69309d9b0b078409a7b0445dac45c23e to your computer and use it in GitHub Desktop.
Save khanlou/69309d9b0b078409a7b0445dac45c23e to your computer and use it in GitHub Desktop.
//
// ObjectStorage.swift
//
// Created by Soroush Khanlou on 9/20/16.
//
import Foundation
protocol ObjectStorageProtocol {
associatedtype Stored
init(location: StorageLocation)
func save(object: Stored)
func fetchObject() -> Stored?
func deleteObject()
}
final class CodableObjectStorage<T: Codable>: ObjectStorageProtocol {
private let fileManager = FileManager.default
let storageLocation: StorageLocation
init(location: StorageLocation) {
self.storageLocation = location
}
func save(object: T) {
guard let appStorageDirectory = appStorageDirectory else { return }
do {
try fileManager.createDirectory(at: appStorageDirectory, withIntermediateDirectories: true, attributes: nil)
let encoder = PropertyListEncoder()
let data = try encoder.encode(object)
try data.write(to: storageURL.unwrap())
} catch {
Analytics.logEvent("Error writing the object.")
print("Error writing the object.")
}
}
func fetchObject() -> T? {
do {
let data = try Data(contentsOf: storageURL.unwrap())
let decoder = PropertyListDecoder()
return try decoder.decode(T.self, from: data)
} catch {
guard (error as NSError).code != NSFileReadNoSuchFileError else { return nil }
Analytics.logEvent("Error reading the object.")
print("Error reading the object.")
return nil
}
}
func deleteObject() {
do {
try fileManager.removeItem(at: storageURL.unwrap())
} catch {
guard (error as NSError).code != NSFileReadNoSuchFileError else { return }
print("Error deleting cache file.")
}
}
private var storageURL: URL? {
return storageLocation.storageLocation
}
private var appStorageDirectory: URL? {
return storageLocation.appStorageDirectory
}
}
final class DisabledObjectStorage<T>: ObjectStorageProtocol {
init(location: StorageLocation) {
}
func save(object: T) {
}
func fetchObject() -> T? {
return nil
}
func deleteObject() {
}
}
//
// StorageLocation.swift
//
// Created by Soroush Khanlou on 9/20/16.
//
import Foundation
enum StorageLocation {
case cache(name: String)
case userData(name: String)
var name: String {
switch self {
case .cache(let name):
return name
case .userData(let name):
return name
}
}
var searchPathDirectory: FileManager.SearchPathDirectory {
switch self {
case .cache:
return .cachesDirectory
case .userData:
return .libraryDirectory
}
}
var fileExtension: String {
switch self {
case .cache:
return ".cache"
case .userData:
return ".userData"
}
}
var fileManager: FileManager {
return FileManager.default
}
var path: String {
return storageLocation?.path ?? ""
}
var storageLocation: URL? {
return appStorageDirectory?.appendingPathComponent(filename)
}
var appStorageDirectory: URL? {
return generalStoreDirectory?.appendingPathComponent("urbanarchive", isDirectory: true)
}
private var generalStoreDirectory: URL? {
let URLs = fileManager.urls(for: searchPathDirectory, in: .userDomainMask)
return URLs.first
}
private var filename: String {
return sanitizedName + fileExtension
}
private var sanitizedName: String {
let invalidFilenameCharacters = CharacterSet(charactersIn: ":/\\?%*|\"<>")
let validName = name.components(separatedBy: invalidFilenameCharacters).joined()
return validName.replacingOccurrences(of: " ", with: "-")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment