Created
April 6, 2023 06:27
-
-
Save jsryudev/450efbb90862eaf9140a1314c0450d54 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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