web-dev-qa-db-ja.com

Firebase:swift)でremoveObserverWithHandleを呼び出すタイミング

ドキュメントによると、オブザーバーが不要になった場合は、observeEventType:withBlockを呼び出してオブザーバーを削除する必要があります。

ViewDidDisAppear内で呼び出されるサンプルを見てきました。また、このメソッドと呼ばれるいくつかのObj-Cコードがdeinit内にありますが、これはSwiftでは必要ありません。

ただし、私の単純なアプリでは、アプリ内にいる限りデータを同期したいと思っています。この場合、observeEventType:withBlockに電話する必要がありますか?

Firebase WebサイトでChat-Swiftサンプルコードを確認しましたが、observeEventType:withBlockが見つかりませんでした。

observeEventType:withBlock:を呼び出さなくても大丈夫という意味ですか。アプリの使用中にオブザーバーをオンにしたい場合はどうすればよいですか?

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

[〜#〜] update [〜#〜]

ジェイとデビッドに感謝します。 ViewWillAppearで観察し、ViewDidDisappearで削除するのは理にかなっていると思います。

ただし、observeEventTypeを使用してノードへの値の変更を監視しており、UIがある場合は更新します。 ViewWillAppearに入れたら:

 override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)

    ref.observeEventType(.Value, withBlock: { snap in {
      // **update UI if there is any Value change** 
    })
  }

viewWillAppearに配置する場合の問題は、値の変更の有無に関係なく、ビューが表示されるたびに呼び出されることです。このため、スナップショットがダウンロードされ、ビューに戻るたびにUIが更新されます。これは逆効果になります。

ChildAdded/ChildRemovedも試しましたが、参照からのパスではなく、最後のノードのみが返されます。

たとえば、ref/child1/child2/child3/valueに追加すると、ChildAddedはchild3/valueのみを返します。

したがって、Valueを監視する必要がある場合は、ViewDidLoadに入れる方が良いように思われますか?このように、ビューがロードされたときにスナップショットを1回取得し、変更があるたびに繰り返しますが、ビューが表示されたという理由だけでスナップショットを取得することはありません。

15
User5103156

@Jayの優れた答えに基づいて構築するには:

UIViewControllerで、プロパティとして参照を作成します。 viewDidLoadで参照を初期化します。 viewWillAppearのイベントを観察します。 viewDidDisappearのオブザーバーを削除します。

class MyViewController: UIViewController {

  var ref: Firebase!

  // Called only on load, great place to initialize
  override func viewDidLoad() {
    super.viewDidLoad()
    ref = Firebase(url: "https://<YOUR-FIREBASE-APP>.firebaseio.com/updates")
  }

  // Can be called many times to go on screen
  // Syncing should only occur when on view to conserve memory
  override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)

    ref.observeEventType(.Value, withBlock: { snap in {
      // do something with the data 
    })
  }

  // Can be called many times to off screen
  // Remove observers on the ref to conserve memory
  override func viewDidDisappear(animated: Bool) {
    super.viewDidDisappear(animated)
    ref.removeAllObservers() 
  }

}

編集ごと:

The problem with putting it in viewWillAppear is that, it gets called every time the view appears, regardless of Value change or not. Because of this, the snapshot is downloaded and my UI gets refreshed every time I return to the view. This becomes counterproductive.

Firebaseはスピードを重視して構築されています。これらは、これらの状況を処理するいくつかの機能を備えているため、クライアントに任せるようなものです。

Firebaseクライアントにはキャッシュが組み込まれています。 viewDidAppearでメガバイトのデータをダウンロードしない限り、更新はわずかです。オブザーバーがviewDidAppearを起動しても、必ずしもデータを再度ダウンロードしているとは限りません。 viewDidAppear関数は、オブザーバーが属する場所です。

参考までに、私はiOSで作業するFirebaseの従業員です。

26
David East

observeEventType:withBlockは、ノードを監視するために使用されるものです。

アプリがノードを監視していると、アプリを終了するか、Firebaseに監視を停止するように指示しない限り、アプリは引き続き監視します。

監視を停止するには、次のように監視を開始したときに返されたハンドルを使用できます。

    //start observing and get a handle
FirebaseHandle handle = [ref observeEventType:FEventTypeValue withBlock:^(FDatasnapshot* snapshot) {
        // do some stuff with the snapshot data
    }];

    [ref removeObserverWithHandle:handle]; //stop observing using the handle

またはこのように

[ref removeAllObservers];
6
Jay

ViewWillAppear()およびviewWillDisappear()での監視と監視の停止は機能しますが、View Controllerが表示されたときに、追加された子値(.added/.valueを監視タイプに使用する場合)が再度発生します。

私はviewDidLoad()で観測を設定し、deinitで観測を停止することを好みます。

オブザベーションを設定した後にdeinitが呼び出されないと言う人もいますが、その理由は、オブザベーションを設定すると、オブザーバーのクロージャが自己を強く保持しているため、deinitが呼び出されないためです。クロージャー内に弱いまたは所有されていないものを設定できます。

これが例です。

class SomeViewController : UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()

    someRef.observe(.childAdded) { [weak self] (snapshot) in
      guard let weakSelf = self else { return }
      ...
    }
  }

  deinit {
    print("deinit called")
    someRef.removeAllObservers()
  }

}

[weak self]と書くことを忘れないでください。そうしないと、deinitが呼び出されることはありません。それが役に立てば幸い。

1
Rian