Firebase: when to call removeObserverWithHandle in swift

User5103156 picture User5103156 · Jul 17, 2015 · Viewed 10.3k times · Source

Documentation says you need to call observeEventType:withBlock to remove an observer if you no longer need it.

I've seen samples where it is called within ViewDidDisAppear. I also find some Obj-C code called this method within deinit, which is not ncessary in Swift.

In my simple app, however, I want data to be synced as long as I am in the app. If this is the case, do I have to call observeEventType:withBlock ever?

I checked the Chat-Swift sample code on Firebase website, and did not find observeEventType:withBlock.

Does it mean it's ok not to call observeEventType:withBlock:. if I want the observer to be on when the app is in use?

Thank you.

UPDATE

Thanks to Jay and David. I see it makes sense to observe in ViewWillAppear and remove it in ViewDidDisappear.

However, I am using observeEventType to monitor any value change to the node and would update UI if there is any. If i put it in ViewWillAppear:

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

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

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.

I have also tried ChildAdded/ChildRemoved, however, it only returns the last node, not the path from my ref:

For instance, if I add to ref/child1/child2/child3/value, ChildAdded would only return child3/value.

So if I have to observe Value, it seems like putting it in ViewDidLoad is better? In this way, it gets the snapshot one time when the view loaded, and would repeat whenever there is a change, but would not obtain the snapshot just because the view appears.

Answer

David East picture David East · Jul 17, 2015

To build upon @Jay's excellent answer:

In a UIViewController, create a reference as a property. Initialize a reference in viewDidLoad. Observe events in viewWillAppear. Remove observers in 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() 
  }

}

Per your edit:

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 is built for speed. These are the kind of things that you leave up to the client because it has several features that handle these situations.

The Firebase client has built-in caching. Unless you're downloading a megabyte of data in viewDidAppear the update is nominal. When the observer fires on viewDidAppear it doesn't necessarily mean it's downloading the data again. The viewDidAppear function is where your observers belong.

FYI, I am a Firebase employee who works on iOS.