Skip to content

Instantly share code, notes, and snippets.

@rnapier
Created April 6, 2019 19:13
Show Gist options
  • Save rnapier/f7f0fa6202b0d6586af188635f54b28b to your computer and use it in GitHub Desktop.
Save rnapier/f7f0fa6202b0d6586af188635f54b28b to your computer and use it in GitHub Desktop.
import Foundation
protocol DataStorage {
subscript(identifier: String) -> Data? { get set }
}
extension UserDefaults: DataStorage {
subscript(identifier: String) -> Data? {
get { return data(forKey: identifier) }
set { set(newValue, forKey: identifier) }
}
}
class DataStore<Key: Hashable & Codable, Value: Codable> {
let identifier: String
private(set) var storage: DataStorage
var dictionary: [Key: Value] {
didSet {
storage[identifier] = try? PropertyListEncoder().encode(dictionary)
}
}
init(identifier: String, storage: DataStorage = UserDefaults.standard) {
self.identifier = identifier
self.storage = storage
let data = storage[identifier] ?? Data()
self.dictionary = (try? PropertyListDecoder().decode([Key: Value].self,
from: data)) ?? [:]
}
subscript(key: Key) -> Value? {
get { return dictionary[key] }
set { dictionary[key] = newValue }
}
}
extension DataStore: Collection {
typealias Index = Dictionary<Key, Value>.Index
typealias Element = Dictionary<Key, Value>.Element
func index(after i: Index) -> Index { return dictionary.index(after: i) }
var startIndex: Index { return dictionary.startIndex }
var endIndex: Index { return dictionary.endIndex }
subscript(position: Index) -> Element { return dictionary[position] }
}
typealias InMemoryDataStorage = [String: Data]
extension InMemoryDataStorage: DataStorage {}
extension InMemoryDataStorage {
func json() -> [String: String] {
return self.compactMapValues { String(bytes: $0, encoding: .utf8) }
}
}
/// A DataStoreStorage that tracks all changes
class TrackingDataStorage: DataStorage {
var storage: [String: Data] {
didSet { history.append(storage) }
}
init(_ storage: [String: Data] = [:]) { self.storage = storage }
var history: [[String: Data]] = []
subscript(identifier: String) -> Data? {
get { return storage[identifier] }
set { storage[identifier] = newValue }
}
}
struct Contact: Codable {
let name: String
let address: String
let phone: String
}
let contacts = DataStore<Int, Contact>(identifier: "contacts")
contacts[123] = Contact(name: "Alice",
address: "123 Main Street",
phone: "(555) 555-1212")
let tracker = TrackingDataStorage()
let ds = DataStore<String, String>(identifier: "TEST",
storage: tracker)
ds["THING"] = "getem"
//ds["THING"]
////ds["THING"] = nil
//ds["THING"]
print(tracker.history)
struct Address: Codable {
let city: String
let state: String
}
struct User: Codable {
let name: String
let email: String
let id: Int
let address: Address
let age: Double
}
let users = [User(name: "alice", email: "[email protected]", id: 1, address: Address(city: "atlanta", state: "GA"), age: 12.3),
User(name: "bob", email: "[email protected]", id: 2, address: Address(city: "boston", state: "MA"), age: 23.4),
User(name: "charlie", email: "[email protected]", id: 3, address: Address(city: "chicago", state: "IL"), age: 34.5),
]
let json = try JSONEncoder().encode(users)
let plist = try PropertyListEncoder().encode(users)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment