Skip to content

Instantly share code, notes, and snippets.

@jsryudev
Created April 6, 2023 06:27
Show Gist options
  • Save jsryudev/450efbb90862eaf9140a1314c0450d54 to your computer and use it in GitHub Desktop.
Save jsryudev/450efbb90862eaf9140a1314c0450d54 to your computer and use it in GitHub Desktop.
// MARK: - LocalStorageType
protocol LocalStorageType {
func storageKey<Element: Storable>(of type: Element.Type) -> String
@discardableResult func append<Element: Storable>(_ value: Element) -> Bool
func element<Element: Storable>(of type: Element.Type) -> Element?
func array<Element: Storable>(of type: Element.Type) -> [Element]
@discardableResult func update<Element: Storable>(_ value: Element) -> Bool
@discardableResult func remove<Element: Storable>(_ value: Element) -> Bool
}
extension LocalStorageType {
func storageKey<Element>(of type: Element.Type) -> String {
[
"dev.jsryu.LocalStorage",
String(describing: type)
]
.joined(separator: ".")
}
func element<Element: Storable>(
of type: Element.Type = Element.self
) -> Element? {
element(of: type)
}
func array<Element: Storable>(
of type: Element.Type = Element.self
) -> [Element] {
array(of: type)
}
}
// MARK: - LocalStorage
final class LocalStorage: LocalStorageType {
private let decoder: JSONDecoder
private let encdoer: JSONEncoder
private let storage: UserDefaults
init(storage: UserDefaults = .standard) {
self.storage = storage
self.decoder = JSONDecoder()
self.encdoer = JSONEncoder()
}
@discardableResult
func append<Element: Storable>(_ value: Element) -> Bool {
var elements = loadData(of: [Element].self) ?? []
elements.append(value)
saveData(elements)
return true
}
func element<Element: Storable>(of type: Element.Type) -> Element? {
let element = loadData(of: type)
return element
}
func array<Element: Storable>(of type: Element.Type) -> [Element] {
let elements = loadData(of: [Element].self) ?? []
return elements
}
@discardableResult
func update<Element: Storable>(_ value: Element) -> Bool {
saveData(value)
return true
}
@discardableResult
func remove<Element: Storable>(_ value: Element) -> Bool {
var elements = loadData(of: [Element].self) ?? []
if let index = elements.firstIndex(where: { $0.hashValue == value.hashValue }) {
elements.remove(at: index)
saveData(elements)
return true
} else {
return false
}
}
}
extension LocalStorage {
private func loadData<Element: Decodable>(of type: Element.Type) -> Element? {
guard let data = storage.object(forKey: storageKey(of: type)) as? Data else {
return nil
}
let element = try? decoder.decode(Element.self, from: data)
return element
}
private func saveData<Element: Encodable>(_ element: Element) {
guard let data = try? encdoer.encode(element) else {
return
}
storage.setValue(
data,
forKey: storageKey(of: Element.self)
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment