post Image
FirebaseのデータをObjectMapperを用いてデータ構造を管理する方法

最初に

この記事は、SwiftFirebaseのデータ構造を、
モデルクラスで管理するためにObjectMapperを利用して、
更に少しアレンジを加えると使いやすくなるのを共有する記事です。

記載時(2016/12/17)のバージョンは下記の通りです。

対象 バージョン
Swift 3.0.1
ObjectMapper 2.2.2
Firebase/Database 3.9.0

FirebaseとObjectMapperの導入方法

Firebase

https://firebase.google.com/docs/database/?hl=ja
公式のチュートリアルが一番わかりやすいので、
Firebase databaseが初めての方は データの取得まで終わらせてください。

ObjectMapper

下記のページで導入方法が記載されています。
https://github.com/Hearst-DD/ObjectMapper#installation

cocoapods
pod 'ObjectMapper', '~> 2.2'
carthage
github "Hearst-DD/ObjectMapper" ~> 2.2

実装

Firebaseのチュートリアルを終えた方はお気付きだと思いますが、モデルクラス化の方法までは記載されていません。

なので、Firebase Realtime Databaseを使ってる方々はどのように使っているんだろう?と思い調べると、様々なやり方がありますが、
色々試した結果、僕の中ではObjectMapperに落ち着きました。

JSONデータ
{
    "Articles": {
        "1" : {
            "title": "一番目の記事"
        },
        "2" : {
            "title": "二番目の記事"
        },
    }
}
ArticleClass
class Article: Mappable {
    var id: String?
    var title: String?

    required init?(map Map: Map){
    }

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

上記のJSONArticleClassObjectMapper を用いて、mappingする時は、下記の処理を行うと思います。

snapshot
let articleId = "1"
FIRDatabase.database().reference().child("articles").child(articleId).observeSingleEvent(of: .value, with: { (snapshot) in
    if let json = snapshot.value as? [String : AnyObject] {
        let article = Mapper<Article>().map(JSON: json)
    }
}

しかし、そのままでは idvalue ではなく key なのでmappingされず、nilのままです。

snapshot
let articleId = "1"
FIRDatabase.database().reference().child("articles").child(articleId).observeSingleEvent(of: .value, with: { (snapshot) in
    if let json = snapshot.value as? [String : AnyObject] {
        let article = Mapper<Article>().map(JSON: json)
        article.id = articleId // 微妙・・><
    }
}

上記の様に実装してもいいのですが、
これだと毎回idを設定するのが面倒なので・・

snapshot
import ObjectMapper
import FirebaseDatabase

extension Mapper {
    public func map(snapshot: FIRDataSnapshot) -> N? {
        guard var json = snapshot.value as? [String : AnyObject] else { return nil }
        json["id"] = snapshot.key as AnyObject
        if let mappingObject = Mapper<N>().map(JSON: json) {
            return mappingObject
        }
        return nil
    }
}

Mapperを拡張し、FIRDataSnapshotを引数で受け取って、生成するようにすると、keyidに代入したマッピングを行うことが出来ます!

snapshot
FIRDatabase.database().reference().child("articles").child(articleId).observeSingleEvent(of: .value, with: { (snapshot) in
    if let json = snapshot.value as? [String : AnyObject] {
        let article = Mapper<Article>().map(JSON: json)
        print("\(article)") // idとtitleが格納されている!
    }
}

感想

僕の中では普段から使っているObjectMapperを利用することに落ち着いたのですが、
ぜひFirebaseをガンガン使ってる方のノウハウを知りたいので、教えてもらえると嬉しいです!

引用元 & 参考


『 Swift 』Article List