Basic KVC implementation.
This file contains 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
//: 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
Pretty cool. Even works in swift 4