Edited at

ObjectMapperでネスト化されたオブジェクトを扱う

More than 3 years have passed since last update.

Objc/SwiftでORMはこれまで使ったことがなかったのですが、手始めにObjectMapperというものを使ってみた。

使い方はREADME.mdに書いてある通りなので省略するとして、


sample.json

"group" {

"id" : 1234,
"name" : "spacemen3",
"color" : 3
"owner" : {
"id" : 99999,
"name" : "ushisantoasobu",
"url" : "xxx.png"
}
}

こんな感じでネスト化されたjsonオブジェクトの、例えばownernameにアクセスしたい場合は、

func mapping(map: Map){

name <- map["owner.name"]
}

のような感じでドットでつなぐことでマッピングできる(これもREADME.mdに書いてある)。

でもこういったデータ構造を扱うときって、


Group.swift

class Group: Mappable {

var identifier = Dynamic<Int>(0)
var name = Dynamic<String>("")
var color = Dynamic<Int>(0)
var ownerId = Dynamic<Int>(0)
var ownerName = Dynamic<String>("")
var ownerUrl = Dynamic<String>("")

required init?(_ map: Map) {
mapping(map)
}

func mapping(map: Map) {
identifier.value <- map["id"]
name.value <- map["name"]
color.value <- map["color"]
ownerId.value <- map["owner.id"]
ownerName.value <- map["owner.name"]
ownerUrl.value <- map["owner.url"]
}
}


とやることはなくて、


User.swift

class User: Mappable {

var identifier = Dynamic<Int>(0)
var name = Dynamic<String>("")
var url = Dynamic<String>("")

required init?(_ map: Map) {
mapping(map)
}

func mapping(map: Map) {
identifier.value <- map["id"]
name.value <- map["name"]
url.value <- map["url"]
}
}



Group.swift

class Group: Mappable {

var identifier = Dynamic<Int>(0)
var name = Dynamic<String>("")
var color = Dynamic<Int>(0)
var owner = User()

required init?(_ map: Map) {
mapping(map)
}

func mapping(map: Map) {
identifier.value <- map["id"]
name.value <- map["name"]
color.value <- map["color"]
user = Mapper<User>().map(dictionary["owner"]) // ここは雰囲気で書いたので当然エラー
}
}


こんな感じで書くのが、データ構造としてスッキリするので普通だと思う。これはあくまで雰囲気で書いたもので、ここをどうやって正しく・簡潔に書くことができるか迷っていた。

で、自分がいまやっているのは、


User.swift

class User: Mappable {

var prefix = ""

var identifier = Dynamic<Int>(0)
var name = Dynamic<String>("")
var url = Dynamic<String>("")

required init?(_ map: Map) {
mapping(map)
}

init(_ map: Map, prefix :String) {
self.prefix = prefix + "."
mapping(map)
}

func mapping(map: Map) {
identifier.value <- map[prefix + "id"]
name.value <- map[prefix + "name"]
url.value <- map[prefix + "url"]
}
}



Group.swift

class Group: Mappable {

var prefix = ""

var identifier = Dynamic<Int>(0)
var name = Dynamic<String>("")
var color = Dynamic<Int>(0)
var owner = User()

required init?(_ map: Map) {
mapping(map)
}

init(_ map: Map, prefix :String) {
self.prefix = prefix + "."
mapping(map)
}

func mapping(map: Map) {
identifier.value <- map["id"]
name.value <- map["name"]
color.value <- map["color"]
user = User(map, prefix: prefix + "owner")
}
}


こんな感じでやっちゃってる。prefixだとかinit(_ map: Map, prefix :String) {は全部共通なので基底クラスがつくれると思うけど、現在思考錯誤中なのでまだやっていない。

でも多分もっといい方法があるのだと思う。ので、ご教授いただけたら幸いです。いや、そもそもObjectMapper自体そんな使われてないのかな。。


追記(2015/7/26)

@keitaoouchi さんよりご指摘いただいて、シンプルに


Group.swift

    func mapping(map: Map) {

identifier.value <- map["id"]
name.value <- map["name"]
color.value <- map["color"]
user <- map["owner"]
}

でいけました。。。ありがとうございました!


追記(2015/8/2)

リストのモデルもそういえばやってなかったと思ったのですが、すんなりいけた。

    var members    = [Member]()

func mapping(map: Map) {
identifier.value <- map["id"]
name.value <- map["name"]
color.value <- map["color"]
user <- map["owner"]
members <- map["members"]
}