//: Playground - noun: a place where people can play | |
import UIKit | |
enum JSONError : ErrorType { | |
case NoValueForKey(String) | |
case TypeMismatch | |
} | |
public class JSONObject { | |
private let dictionary: [String:AnyObject] | |
public init(dictionary: [String:AnyObject]) { | |
self.dictionary = dictionary | |
} | |
func valueForKey<A>(key: String) throws -> A { | |
let pathComponents = key.componentsSeparatedByString(".") | |
var accumulator: Any = dictionary | |
for component in pathComponents { | |
if let dict = accumulator as? [String:AnyObject] { | |
if let value = dict[component] { | |
accumulator = value | |
continue | |
} | |
} | |
throw JSONError.NoValueForKey(key) | |
} | |
if let value = accumulator as? A { | |
return value | |
} | |
else { | |
throw JSONError.TypeMismatch | |
} | |
} | |
func objectForKey(key: String) throws -> JSONObject { | |
let dict: [String:AnyObject] = try valueForKey(key) | |
return JSONObject(dictionary: dict) | |
} | |
func optionalForKey<A>(key: String) throws -> A? { | |
do { | |
return try valueForKey(key) | |
} | |
catch JSONError.NoValueForKey { | |
return nil | |
} | |
catch { | |
throw JSONError.TypeMismatch | |
} | |
} | |
func objectOptionalForKey(key: String) throws -> JSONObject? { | |
let dict: [String:AnyObject]? = try optionalForKey(key) | |
return dict.map(JSONObject.init) | |
} | |
} | |
struct Person { | |
var name: String | |
var age: Int | |
var height: Double | |
var street: String? | |
init(json: JSONObject) throws { | |
try name = json.valueForKey("name") | |
try age = json.valueForKey("age") | |
try height = json.valueForKey("height") | |
try street = json.optionalForKey("address.street") | |
} | |
} | |
do { | |
let json = JSONObject(dictionary: ["name": "Bob", "age": 26.5, "height": 5.75, "address": ["street": "A Street"]]) | |
let foo: Int = try json.valueForKey("age") | |
let person = try Person(json: json) | |
} | |
catch let JSONError.NoValueForKey(key) { | |
print("Didn't find value for key: \(key)") | |
} | |
catch { | |
print("Wrong type") | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
optionalForKey() doesn't work. A small adjustment is needed:
func optionalForKey(key: String) throws -> A? {
do {
return try valueForKey(key) as A // <-- "as A" otherwise the return value of valueForKey is optional and always produces a TypeMismatch error.
}