Swiftで面倒なJSONの取り扱いをさらに10倍便利にするclass JSON 

[Swiftで面倒なJSONの取り扱いを10倍便利にするSwiftyJSON]をもってしても、まだJavaScriptよりも面倒だったのが悔しかったので書きました。

[Swiftで面倒なJSONの取り扱いを10倍便利にするSwiftyJSON]: http://qiita.com/yukihamada/items/9b0067f905418105a2c6

* https://github.com/dankogai/swift-json/

Synopsis
--------

AnyObjectなSwiftオブジェクトも、こうして JSON Stringにできます。

````swift
let obj:[String:AnyObject] = [
    "array": [JSON.null, false, 0, "",[],[:]],
    "object":[
        "null":   JSON.null,
        "bool":   true,
        "int":    42,
        "double": 3.141592653589793,
        "string": "a α\t弾\n?",
        "array":  [],
        "object": [:]
    ],
    "url":"http://blog.livedoor.com/dankogai/"
]

let json = JSON(obj)
json.toString()
// "{\"array\":[null,false,0,\"\",[],{}],
//  \"object\":{\"int\":42,\"double\":3.141592653589793,
//  \"string\":\"a α\t弾\n?\",\"object\":{},\"null\":null,
//  \"bool\":true,\"array\":[]},
//  \"url\":\"http://blog.livedoor.com/dankogai/\"}"
````

もちろん文字列からも

````swift
let json = JSON.parse("{\"array\":[...}")
````

URLからも。

````swift
let json = JSON.fromURL("http://api.dan.co.jp/jsonenv")
````

### JSONの歩き方。

添字で葉までいって、型をあわせるだけ。

````swift
json["object"]["null"].asNull       // NSNull()
json["object"]["bool"].asBool       // true
json["object"]["int"].asInt         // 42
json["object"]["double"].asDouble   // 3.141592653589793
json["object"]["string"].asString   // "a α\t弾\n?"

json["array"][0].asNull             // NSNull()
json["array"][1].asBool             // false
json["array"][2].asInt              // 0
json["array"][3].asString           // ""
````

[SwiftyJSON]と同様、存在しない添字にアクセスしても爆発しません。その代わり発生したエラーをほいほいと次のメソッドに投げていきます。Optional ChainならぬNSError Chainといったところでしょうか。

[SwiftyJSON]: https://github.com/lingoer/SwiftyJSON

````swift
if let b = json["noexistent"][1234567890]["entry"].asBool {
    // ....
} else {
    let e = json["noexistent"][1234567890]["entry"].asError
    println(e)
} // Error Domain=JSONErrorDomain Code=404 "["noexistent"] not found" UserInfo=0x10064bfc0 {NSLocalizedDescription=["noexistent"] not found}
````

ここまではSwiftyJSONと同様なのですが、一つ困ったことがあったのです。

SwiftyJSONのJSONValueは、`enum`だったのです。

なんで`enum`だと困るのでしょう?

### `class JSON`は継承可

ここでJavaScriptにおけるJSONの取り扱いを見てみましょう。

````JavaScript
//json["object"]["string"] vs...
  json.object.string
````

はい、さらに短い。オブジェクトの一分岐ごとに4文字も。Swift(というか厳密には`NSDictionary`)では添字を使わざるを得なかったところを、JavaScriptではプロパティで行けるからです。

でもプロパティの追加は、何もJavaScriptの専売特許ではありませんよね?

こうすればいけるではありませんか?

````swift
//// schema by subclassing
class MyJSON : JSON {
    override init(_ obj:AnyObject){ super.init(obj) }
    override init(_ json:JSON)  { super.init(json) }
    var null  :NSNull? { return self["null"].asNull }
    var bool  :Bool?   { return self["bool"].asBool }
    var int   :Int?    { return self["int"].asInt }
    var double:Double? { return self["double"].asDouble }
    var string:String? { return self["string"].asString }
    var url:   String? { return self["url"].asString }
    var array :MyJSON  { return MyJSON(self["array"])  }
    var object:MyJSON  { return MyJSON(self["object"]) }
}
````

行けました!

````swift
let myjson = MyJSON(obj)
myjson.object.null      // NSNull?
myjson.object.bool      // Bool?
myjson.object.int       // Int?
myjson.object.double    // Double?
myjson.object.string    // String?
myjson.url              // String?
````

JavaScriptではゼロ円でやってくれる連想配列のプロパティ化のために、一行メソッドの羅列とはいえclassを一個定義するのはめんどくさくも感じます。その一方、ソースコードできちんと定義しておくことじゃ、意図しないプロパティをtypoで作ってしまうことがありえないことも意味します。そもそもコンパイル通りませんし、IDEによる補完もこれで効くようになります。さらに各プロパティ(というかgetter)で入力検証したりするのもこれで自由自在です。

Swiftにはプリミティブでない型が三種類もあります。が、`class`には他の二つと二つの大きな違いがあります。一つは値の代入で、残りの二つが値渡しなのに対して参照渡しであること。そしてもう一つが、継承をサポートしていることです。

`struct`や`enum`にも、新たなプロパティを追加するのは`extension`で可能です。が、これだとオールオアナッシングなんですよね。サイトごとにschemaを変えたいってのが出来ない。

この問題があるので、`Array`や`Dictionary`にもclass版が欲しいところではありますね。

Dan the Man with too Much Data to (De)?serialize

追記[2016.01.29]: Swift 2にも対応しているのみならず、Playgroundも付いています。