Search code examples
iosswiftfirebasefirebase-realtime-databaseobservers

Firebase removeAllObservers() keeps making calls when switching views -Swift2 iOS


I read other stack overflow q&a's about this problem but it seems to be a tabBarController issue which I haven't found anything on.

I have a tabBarController with 3 tabs. tab1 is where I successfully send the info to Firebase. In tab2 I have tableView which successfully reads the data from tab1.

In tab2 my listener is in viewWillAppear. I remove the listener in viewDidDisappear (I also tried viewWillDisappear) and somewhere in here is where the problem is occurring.

override func viewDidDisappear(animated: Bool) {
    self.sneakersRef!.removeAllObservers()
    //When I tried using a handle in viewWillAppear and then using the handle to remove the observer it didn't work here either
    //sneakersRef!.removeObserverWithHandle(self.handle)
   }

Once I switch from tab2 to any other tab, the second I go back to tab2 the table data doubles, then if I switch tabs again and come back it triples etc. I tried setting the listener inside viewDidLoad which prevents the table data from duplicating when I switch tabs but when I send new info from tab1 the information never gets updated in tab2.

According to the Firebase docs and pretty much everything else I read on stackoverflow/google the listener should be set in viewWillAppear and removed in viewDidDisappear.

Any ideas on how to prevent my data from duplicating whenever I switch between back forth between tabs?

tab1

import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase

class TabOneController: UIViewController{

var ref:FIRDatabaseReference!
@IBOutlet weak var sneakerNameTextField: UITextField!

override func viewDidLoad() {
      super.viewDidLoad()
      self.ref = FIRDatabase.database().reference()
}

@IBAction func sendButton(sender: UIButton) {

      let dict = ["sneakerName":self.sneakerNameTextField.text!]

      let usersRef = self.ref.child("users")
      let sneakersRef = usersRef.child("sneakers").childByAutoID()

      sneakersRef?.updateChildValues(dict, withCompletionBlock: {(error, user) in
                if error != nil{
                    print("\n\(error?.localizedDescription)")
                }
            })
      }
}

tab2

import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase

class TabTwoController: UITableViewController{

@IBOutlet weak var tableView: UITableView!

var handle: Uint!//If you read the comments I tried using this but nahhh didn't help
var ref: FIRDatabaseReference!
var sneakersRef: FIRDatabaseReference?
var sneakerArray = [String]()

override func viewDidLoad() {
      super.viewDidLoad()
      self.ref = FIRDatabase.database().reference()
    }

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

      let usersRef = self.ref.child("users")
      //Listener
      self.sneakersRef = usersRef.child("sneakers")

      //I tried using the handle
      //---self.handle = self.sneakersRef!.observeEventType(.ChildAdded...

      self.sneakersRef!.observeEventType(.ChildAdded, withBlock: {(snapshot) in

      if let dict = snapshot.value as? [String:AnyObject]{

        let sneakerName = dict["sneakerName"] as? String
        self.sneakerArray.append(sneakerName)

        dispatch_async(dispatch_get_main_queue(), {
                self.tableView.reloadData()
       })

     }

   }), withCancelBlock: nil)
 }

//I also tried viewWillDisappear
override func viewDidDisappear(animated: Bool) {

        self.sneakersRef!.removeAllObservers()

        //When I tried using the handle to remove the observer it didn't work either
        //---sneakersRef!.removeObserverWithHandle(self.handle)
   }


func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      return self.sneakerArray.count
  }

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
      let cell = self.tableView.dequeueReusableCellWithIdentifier("sneakerCell", forIndexPath: indexPath)
      cell.textLabel?.text = sneakerArray[indexPath.row]
      return cell
  }
}

tab3 does nothing. I just use it as an alternate tab to switch back and forth with


Solution

  • The removeAllObservers method is working correctly. The problem you're currently experiencing is caused by a minor missing detail: you never clear the contents of sneakerArray.


    Note: there's no need for dispatch_async inside the event callback. The Firebase SDK calls this function on the main queue.