Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
113
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

@takayama

[Swift] ObjectMapper で JSON データのマッピング

こんにちは。

なんつうかもう、気付いたらそこら中 JSON ばっかりですね。サーバから JSON のデータを持ってきてパースしてる人は世界中にどんだけいるんでしょーか。

取得した JSON は、データ構造に応じて適切にモデルクラスに落とし込みたいですよね。ですよね? Swift でどうやるか調べたところ、ObjectMapper を使うとそんなこんながとても簡単に実現できました。こいつはなかなか便利な奴です。

Alamofire と組み合わせたり Realm と組み合わせたりもできて素敵です。今回は書いてませんが、JSON のキャッシュとして Realm と一緒に使ってます。あんまり意識せずにすんなり使えるのがいいですね。

セットアップ

CocoaPods や Carthage でインストールできますので Readme をご参考に

基本的な使い方

たとえば、ユーザデータが入った JSON があるとして。

[
    { "name": "takayama" },
    { "name": "takahashi" },
    { "name": "yamada" }
]

これに対応するクラスを作って。

class User: Mappable {
    var name: String?

    required init?(_ map: Map) {
    }

    func mapping(map: Map) {
        name <- map["name"]
    }
}

こんな風に読み込む。

let users: [ User ]? = Mapper<User>().mapArray(jsonString)
print(users?[0].name) // => Optional("takayama")

たとえば JSON の中に name がなかった場合は user.name の値は nil になりますけど、var name: String = "" とかやっておけば空文字になりますし、var name: String = "Default" とかだと特定の値をデフォルト値にできます。

まあ基本的な使い方はオリジナルのドキュメント見ればわかります。ここまでは簡単です。

型変換

例えば JSON のデータ方が文字列型だった場合に数値型に変換してくれるような仕組みやらがあるのですが、この辺がなかなか理解できなくて苦労しました。特に難しかったのが NSDate への変換です。

Custom Transforms という仕組みがあって、ドキュメントを読むと DateTransform というのを使って NSDate に対応しているように見えます。ただこれ、データソースが UnixTime を想定しているんですよね。1456727500 的な。我々のデータは yyy-MM-dd HH:mm:ss なのでこのままでは無理ゲー。

class User: Mappable {
    var birthday: NSDate?

    required init?(_ map: Map) {

    }

    func mapping(map: Map) {
        birthday <- (map["birthday"], DateTransform())
    }
}

Custom Transforms まわりのソースを参照するとサブクラスがいくつかあって、その中の CustomDateFormatTransform というやつがそのものずばりで使えました。TransformType クラスを継承すれば自作もできそうです。

そんでもって CustomDateFormatTransform を使うとこんな簡単に…!

class User: Mappable {
    var birthday: NSDate?

    required init?(_ map: Map) {

    }

    func mapping(map: Map) {
        birthday <- (map["birthday"], CustomDateFormatTransform(formatString: "yyyy-MM-dd HH:mm:ss"))
    }
}

他に URLTransform を使うと NSURL にできます。

var url: NSURL?

func mapping(map: Map) {
    url <- (map["url"], URLTransform())
}

EnumTransform というのもあります。

enum DataType: Int {
    case Unknown, Work, Home
}

...

var type: DataType?

func mapping(map: Map) {
    type <- (map["type"], EnumTransform<DataType>())
}

全部入り

今回紹介したやつで作るとこんな感じでしょうか。

class User: Mappable {
    enum DataType: Int {
        case Unknown, Work, Home
    }

    var name: String?
    var birthday: NSDate?
    var type: DataType = .Unknown
    var url: NSURL?

    required init?(_ map: Map) {
    }

    func mapping(map: Map) {
        name     <- map["name"]
        birthday <- (map["birthday"], CustomDateFormatTransform(formatString: "yyyy-MM-dd HH:mm:ss"))
        type     <- (map["type"], EnumTransform<DataType>())
        url      <- (map["url"], URLTransform())
    }
}

JSON

[
{
    "name": "takayama",
    "birthday": "1999-09-09 00:00:00",
    "type": 2,
    "url": "http://twitter.com/takayama"
},
{
    "name": "takahashi",
    "birthday": "1999-01-01 00:00:00",
    "type": 1,
    "url": "http://www.example.com/"
},
{
    "name": "yamada",
    "birthday": "2016-02-29 15:20:00",
    "type": 2,
    "url": "http://qiita.com/takayama"
}
]

実行してみる。

let users: [ User ]? = Mapper<User>().mapArray(jsonString)

for user in users! {
   print(user.name, user.birthday, user.type.rawValue, user.url)
}

出力結果。

Optional("takayama") Optional(1999-09-08 15:00:00 +0000) 2 Optional(http://twitter.com/takayama)
Optional("takahashi") Optional(1998-12-31 15:00:00 +0000) 1 Optional(http://www.example.com/)
Optional("yamada") Optional(2016-02-29 06:20:00 +0000) 2 Optional(http://qiita.com/takayama)
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
113
Help us understand the problem. What are the problem?