Basic KVC implementation.
//: Playground - noun: a place where people can play | |
import Cocoa | |
struct KVCTypeInfo : Hashable { | |
let key: String | |
let type: Any.Type | |
// Terrible hash value, just FYI. | |
var hashValue: Int { return key.hashValue &* 3 } | |
} | |
func ==(lhs: KVCTypeInfo, rhs: KVCTypeInfo) -> Bool { | |
return lhs.key == rhs.key && lhs.type == rhs.type | |
} | |
protocol KeyValueCodable : _KeyValueCodable { | |
mutating func setValue<T>(value: T, forKey: String) throws | |
func getValue<T>(forKey: String) throws -> T | |
} | |
protocol _KeyValueCodable { | |
static var _codables: [KVCTypeInfo] { get } | |
var _kvcstore: Dictionary<String, Any> { get set } | |
} | |
extension KeyValueCodable { | |
mutating func setValue<T>(value: T, forKey: String) { | |
for codable in Self._codables { | |
if codable.key == forKey { | |
if value.dynamicType != codable.type { | |
fatalError("The stored type information does not match the given type.") | |
} | |
_kvcstore[forKey] = value | |
return | |
} | |
} | |
fatalError("Unable to set the value for key: \(forKey).") | |
} | |
func getValue<T>(forKey: String) -> T { | |
guard let stored = _kvcstore[forKey] else { | |
fatalError("The property is not set; default values are not supported.") | |
} | |
guard let value = stored as? T else { | |
fatalError("The stored value does not match the expected type.") | |
} | |
return value | |
} | |
} | |
struct Person : KeyValueCodable { | |
static var _codables: [KVCTypeInfo] { return [ _idKey, _fnameKey ]} | |
var _kvcstore: Dictionary<String, Any> = [:] | |
} | |
extension Person { | |
private static let _idKey = KVCTypeInfo(key: "id", type: Int.self) | |
private static let _fnameKey = KVCTypeInfo(key: "fname", type: String.self) | |
init(id: Int, fname: String) { | |
self.id = id | |
self.fname = fname | |
} | |
var id: Int { | |
get { return getValue("id") as Int } | |
set { setValue(newValue, forKey: "id") } | |
} | |
var fname: String { | |
get { return getValue("fname") as String } | |
set { setValue(newValue, forKey: "fname") } | |
} | |
} | |
var p = Person(id: 123, fname: "David") | |
p.id | |
p.fname | |
let id: Int = p.getValue("id") | |
let fname: String = p.getValue("fname") | |
p.setValue(21, forKey: "id") | |
p.setValue("Sally", forKey: "fname") | |
let id1: Int = p.getValue("id") | |
let fname1: String = p.getValue("fname") | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
Pretty cool. Even works in swift 4