2018年3月8日木曜日

Firebase Swift で observe が複数回コールされてしまう場合に確認すること

概要

Firebase からデータを取得する場合 observe or observeSingleEvent を使うと思います
observeSingleEvent の場合は特に問題ないのですがリアルタイムでデータを取得したい場合には observe を使います
その場合に何故か 1 度しかデータを更新していないのに observe が複数回コールされる現象に遭遇したので対策を紹介します

環境

  • macOS 10.13.2
  • Xcode 9.2 (9C40b)
  • Firebase 4.8.2

確認する点

いくつか紹介します

単純にデータを複数回更新していないか

Swift からデータを更新する際には setValue or updateChildValues を使うと思います
単純にこれらが複数回コールされていないか確認しましょう
例えば touchDown などのイベントが発生したら上記メソッドを呼ぶようなケースだとすると連打などの対策をしていないと同じデータが複数回更新される可能性があります

Firebase の場合データが同じであっても更新イベントがあれば observe してしまいます

observe を removeObserver していない

自分はこっちでハマリました
observe の場合 removeObserver をしないといくら View が変わってもデータの監視が続いてしまうようです
これは SpriteKit でも同様で SKScene が変わった時に removeObserver していないと複数回コールされてしまうことがあります

removeObserver は例えば以下のように使います

var bmref = DatabaseReference()
var handler: UInt = 0

bmref = rootRef.child("path/to/data")
handler = bmref.observe(.value, with: { (snapshot) in
    bmref.removeObserver(withHandle: handler)
    move(to: scene)
})

move(to :scene) は適当にこちらで定義したシーンを移動するためのメソッドです
要するにシーンの移動直前に removeObserver を呼ぶようにしましょう
removeObserver の引数には observe を識別するためのハンドラが必要です
これは observe を登録した際の戻り値として取得することができます
ハンドラはインスタンス変数などにして別のメソッドからも参照できるようにしておきましょう

これで observe を削除することができます

observe が複数コールされる場合の影響

自分の場合は SpriteKit 上で使っていたのですが observe が複数回コールされることで fps が低下するという現象が発生しました

具体的に言うと SKAction.move などで動いているノードがある状態で observe が複数回コールされるとノードが一瞬 (0.5 - 1 秒ほど) 停止する状態になります
これが必要最低限のみコールされるようになることで fps が落ちることなくノードが動き続けてくれます

最後に

Swift + Firebase で observe が複数回コールされてしまう場合の対策を紹介しました
observe が削除されていない場合には削除するように修正してみてください

それでも重い、fps が落ちるという場合には単純に Firebase に対してアクセスしすぎていないか確認してみてください (1 秒間に 100 回データを更新するような処理をしていないかなど)

そういう場合にはずっと observe しないで定期的に observeSingleEvent するような仕組みに変更するようにしてみてください

0 件のコメント:

コメントを投稿