Skip to content

Instantly share code, notes, and snippets.

@jeremychone
Last active August 29, 2015 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeremychone/70e8143883c01a6946b4 to your computer and use it in GitHub Desktop.
Save jeremychone/70e8143883c01a6946b4 to your computer and use it in GitHub Desktop.
Simple and convenient Json wrapper for the AnyObject returned by NSJSONSerialization
import Foundation
//
// Json.swift
//
// Simple and convenient JSON wrapper of a AnyObject returned by the NSJSONSerialization parser.
//
// NEXT: probably want to split the promise (done/fail) from the future part (the resolve/reject)
//
// Jeremy Chone 2015-06-21
public class Json : CustomStringConvertible{
enum JsonError: ErrorType{
case CANT_PARSE(ErrorType)
}
let jsonObject: AnyObject
public var description: String { get {
return (jsonObject.description)!
}}
// --------- Constructors & Factories --------- //
public init(jsonObject: AnyObject){
self.jsonObject = jsonObject
}
static public func parse(jsonString jsonString: String) throws -> Json{
do{
let jsonData = jsonString.dataUsingEncoding(NSUTF8StringEncoding)
let jsonObject = try NSJSONSerialization.JSONObjectWithData(jsonData!, options: NSJSONReadingOptions.AllowFragments)
return Json(jsonObject: jsonObject)
} catch let e {
throw JsonError.CANT_PARSE(e)
}
}
// --------- /Constructors & Factories --------- //
// --------- Subscripts --------- //
// Convenience for get(:[String]).
// e.g. json["username"] or json["company","name"]
public subscript(names: String...) -> Json? {
return get(names)
}
// --------- /Subscripts --------- //
// --------- Public APIs --------- //
// Possibly return a new Json object targeted by a list of names for the path
public func get(names: [String]) -> Json?{
// if empty names, we can shortcut and return self
if (names.isEmpty){
return self;
}
// attempt to get the anyObject for this path names
guard let obj = anyObject(names) else{
return nil
}
// create and return the new Json object only if found
return Json(jsonObject: obj)
}
// variadic convenience
public func get(names: String...) -> Json?{
return get(names);
}
// If the targeted jsonObject is an [AnyObject], this will map it to a [Json]
public func array(names: String...) -> [Json]? {
guard let objs = anyObject(names) as? [AnyObject] else {
return nil
}
return objs.map({Json(jsonObject:$0)})
}
// convenience method for get(names) as? String
public func string(names: String...) -> String?{
return anyObject(names) as? String
}
// convenience method for get(names) as? Int
public func int(names: String...) -> Int?{
return anyObject(names) as? Int
}
// convenience method for get(names) as? Double
public func double(names: String...) -> Double?{
return anyObject(names) as? Double
}
// convenience method for get(names) as? Boolean
public func bool(names: String...) -> Bool?{
return anyObject(names) as? Bool
}
// Possibly return an AnyObject targetted by the set of names
// If names is an empty array, returns this json AnyObject
// e.g. to get "company.name" AnyObject?, you call anyObject(["company","name"])
public func anyObject(names: [String]) -> AnyObject?{
var currentObj: AnyObject? = jsonObject
if names.isEmpty {
return currentObj
}
for path in names {
guard let dic = currentObj as? Dictionary<String,AnyObject> else {
currentObj = nil
break
}
currentObj = dic[path]
if (currentObj == nil){
break;
}
}
return currentObj;
}
// Variadic convenience to allow the anyObject("company","name")
public func anyObject(names: String...) -> AnyObject?{
return anyObject(names)
}
// --------- /Public APIs --------- //
}
//: [Previous](@previous)
import Foundation
import XCPlayground
let filePath = NSBundle.mainBundle().pathForResource("playground-test", ofType: "json")
// get the contentData
let contentData = NSFileManager.defaultManager().contentsAtPath(filePath!)
// get the string
let jsonString = NSString(data: contentData!, encoding: NSUTF8StringEncoding) as? String
// print
//print("filepath: \(filePath!)")
//if let c = jsonString {
// print("content: \n\(c)")
//}
do {
let json = try Json.parse(jsonString: jsonString!)
if let val = json.anyObject("username") as? String{
print(val)
}
print(json.int("id")!)
print("--- json.username")
print(json.string("username"))
print(json.get("username")?.string())
print(json["username"]?.string())
print(json["username","name"]) // should return nil
print("--- json.company.name")
print(json["company","name"])
print(json["company"]?["name"])
print("--- json.company.address.zipcode")
print(json["company"]?["address"]?["zipcode"])
print(json["company","address","zipcode"]?.int())
print(json["company","address","zipcode"]?.double())
print(json["company","address","zipcode"]?.string())
print("--- json.company.address.hq")
print(json["company"]?["address"]?["hq"])
print(json["company"]?["address"]?["hq"]?.get())
print(json["company"]?["address"]?["hq"]?.bool())
print(json.bool("company","address","hq"))
print(json["company"]?["address"]?["hq"]?.anyObject() as? Bool)
print("--- json.languages")
let jlanguages = json["languages"]?.array()
print(jlanguages?[0].string("name"))
} catch let e {
print("Playground Error \(e)")
}
jc
123
--- json.username
Optional("jc")
Optional("jc")
Optional("jc")
nil
--- json.company.name
Optional(Netscape)
Optional(Netscape)
--- json.company.address.zipcode
Optional(94043)
Optional(94043)
Optional(94043.0)
nil
--- json.company.address.hq
Optional(1)
Optional(1)
Optional(true)
Optional(true)
Optional(true)
--- json.languages
Optional("Java")
{
"username":"jc",
"id": 123,
"company": {
"founded": 1994,
"name": "Netscape",
"address": {
"city": "Mountain View",
"zipcode": 94043,
"hq": true
}
},
"languages": [
{"name":"Java", "rank": 8},{"name":"Javascript", "rank": 9},
{"name":"Swift", "rank": 5},{"name":"Python", "rank": 4}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment