Skip to content

Instantly share code, notes, and snippets.

@owensd

owensd/kvc.swift Secret

Created July 14, 2015 21:27
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save owensd/82af8e362273e46d70f9 to your computer and use it in GitHub Desktop.
Save owensd/82af8e362273e46d70f9 to your computer and use it in GitHub Desktop.
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")
@eonist
Copy link

eonist commented Aug 23, 2017

Pretty cool. Even works in swift 4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment