Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

最初に

この記事は、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をガンガン使ってる方のノウハウを知りたいので、教えてもらえると嬉しいです!

引用元 & 参考

syamaoka
Swift, Objective-C, Node.js, PHPを中心に勉強しています。 好き:MMO RPG 嫌い:差し込み, 二度手間
dena_coltd
    Delight and Impact the World
https://dena.com/jp/
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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした