LoginSignup
17
17

More than 5 years have passed since last update.

SwiftでEnumで快適にJson扱うライブラリEJson

Last updated at Posted at 2015-02-11

Functional Programming in Swift
http://www.objc.io/books/

を読みながら、どうしてもEnumでJsonを表現するライブラリを作ってみたかったのです。
型セーフ、スレッドセーフで、案外いい感じです。
実際違ったアプローチで遊んでみたいという思いがこれを作らせました。
新しいビジョンが得られれば幸いです。

そこ、SwiftyJSONでいいとか言わない! まったくもう!

リポジトリはこちら
https://github.com/Ushio/EnumJson

※ また、Swift 1.2 なのでご注意ください。
※ Carthageに対応しています。

定義

public enum Json {
    case JObject  ([String : Json])
    case JArray   ([Json])
    case JNumber  (NSNumber)
    case JString  (String)
    case JBoolean (Bool)
    case JNull
}

とてもシンプルです。Dictionary,Arrayが一段挟まっているので再帰的定義に小細工は必要ありません。
要するにこれがやりたかっただけです。

生成

let json: Json = [
    "string" : "string_value",
    "number_double" : 10.5,
    "number_int" : 15,
    "boolean" : true,
    "null" : nil,
    "array" : ["red", "green", "blue"],
    "object" : [
        "one" : 1,
        "two" : 2,
        "three" : 3
    ]
]

もろもろConvertibleが用意されているので、直感的に記述できます。

書き出しや読み込み


if let data = json.jsonData {
  // do something
}
if let json = EJson(data: data) {
  // do something
}

アクセスショートカット

let json: Json = [
    "string" : "string_value",
    "number_double" : 10.5,
    "number_int" : 15,
    "boolean" : true,
    "null" : nil,
    "array" : ["red", "green", "blue"],
    "object" : [
        "one" : 1,
        "two" : 2,
        "three" : 3
    ]
]
let string_value: String? = json["string_value"]?.string
let green: String? = json["array" ~> 1]?.string
let three: Double? = json["object" ~> "three"]?.double

値のセット

subscriptで値をセットします。

var json: Json = [:]

json["string_key"] = "string"
json["key1" ~> "key2"] = true
json["key3"] = "a"
json["key3"] = "c"

let yes = json == [
    "string_key" : "string",
    "key1" : ["key2" : true],
    "key3" : "c"
]

削除

nilをsubscriptで代入することで削除できます。

var json: Json = [
    "string" : "string_value",
    "number_double" : 10.5,
    "number_int" : 15,
    "array" : ["red", "green", "blue", "blue"],
    "object" : [
        "one" : 1,
        "two" : 2,
        "three" : 3
    ]
]

json["number_int"] = nil
json["array" ~> 1] = nil
json["object" ~> "one"] = nil

let yes = json == [
    "string" : "string_value",
    "number_double" : 10.5,
    "array" : ["red", "blue", "blue"],
    "object" : [
        "two" : 2,
        "three" : 3
    ]
]

オブジェクトへのマッピング

Swift 1.2ではifでシンプルに記述できるようになりました。

struct User {
    let number: Double
    let name: String

    static func fromJson(json: Json) -> User? {
        if
            let number = json["number"]?.double,
            let name = json["name"]?.string
        {
            return User(number: number, name: name)
        }
        return nil
    }
}

let json: Json = [
    "number" : 17.4,
    "name" : "ken"
]

if let user = User.fromJson(json) {
    // do something
}

※<*>演算子はEnumJsonから外すことにしました。ただ面白い手法なので、興味のある方はこちらの記事をお勧めします。
http://qiita.com/koher/items/95583f58a443f6a33c28

まとめ

単なる一発ネタだったのですが、組み立ててみると案外使えるものができたような気がしないでもないです(弱)

TODO リスト

  • 名前空間(対応済み)
  • asXxx => xxx (対応済み)
  • Carthage対応 (対応済み)
  • 数値精度問題対応 (不完全ではあるが、一部対応済み)

Carthage対応し、バージョン1.0を正式に決めました。
初期バージョンからは要素の削除や追加の方法がよりシンプルになるなど微調整が含まれています。

17
17
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
17