Will Jackson
Will Jackson

Reputation: 345

Populating UITableViewController With Firebase Data Swift, Xcode 7

I am working with swift in Xcode 7. I am totally new to Swift, Xcode, and Firebase. I would like to have three UITableViewControllers in my iOS app. The first two TableView controllers will need dynamic content and the third TableView controller will need static content. I would like for the second and third TableView controllers to display data based on what is pressed on the previous TableView controller. All of the data will come from my Firebase. I have no idea where to start. Please point me in the right direction! Thank you!

Upvotes: 1

Views: 8694

Answers (2)

DogCoffee
DogCoffee

Reputation: 19966

I do it slightly different when I have a UITableViewController, especially for those that can push to another detail view / or show a modal view over the top.

Having the setObserver in ViewDidAppear works well. However, I didnt like the fact that when I looked into a cells detail view and subsequently popped that view, I was fetching from Firebase and reloading the table again, despite the possibility of no changes being made.

This way the observer is added in viewDidLoad, and is only removed when itself is popped from the Nav Controller stack. The tableview is not reloaded unnecessarily when the viewAppears.

var myRef:FIRDatabaseReference = "" // your reference

override func viewDidLoad() {
    super.viewDidLoad()
    setObserver()
}

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

    // only called when popped from the Nav Controller stack
    // if I push to another detail view my observer will remain active
    if isBeingDismissed() || isMovingFromParentViewController() {
        myRef.removeAllObservers()
    }
}

func setObserver() {

    myRef.observeEventType(.Value, withBlock: { snapshot in

        var newThings = [MyThing]()

        for s in snapshot.children {
            let ss = s as! FIRDataSnapshot
            let new = MyThing(snap: ss) // convert my snapshot into my type
            newThings.append(new)
        }

        self.things = newThings.sort{ $0.name < $1.name) } // some sort
        self.tableView.reloadData()
    })
}

I also use .ChildChanged .ChildDeleted and .ChildAdded in UITableViews. They work really well and allow you use UITableView animations. Its a little more code, but nothing too difficult.

You can use .ChildChanged to get the initial data one item at a time, then it will monitor for changes after that.

If you want all your data at once in the initial load you will need .Value, I suggest you use observeSingleEventOfType for your first load of the tableview. Just note that if you also have .ChildAdded observer you will also get an initial set of data when that observer is added - so you need to deal with those items (i.e. don't add them to your data set) otherwise your items will appear twice on the initial load.

Upvotes: 2

David East
David East

Reputation: 32604

This question is broad, in that it asks how to do three different tasks.

I think you'll be better off getting answers if you only ask for one thing at a time.

I can help you with populating a UITableViewController with Firebase.

class MyTableViewController: UITableViewController {
  // your firebase reference as a property
  var ref: Firebase! 
  // your data source, you can replace this with your own model if you wish
  var items = [FDataSnapshot]() 

  override func viewDidLoad() {
    super.viewDidLoad()
    // initialize the ref in viewDidLoad
    ref = Firebase(url: "<my-firebase-app>/items")
  }

  override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    // listen for update with the .Value event
    ref.observeEventType(.Value) { (snapshot: FDataSnapshot!) in

      var newItems = [FDataSnapshot]()

      // loop through the children and append them to the new array
      for item in snapshot.children {
        newItems.append(item as! FDataSnapshot)
      }

      // replace the old array
      self.items = newItems
      // reload the UITableView
      self.tableView.reloadData()
    }
  } 
}

This technique uses the .Value event, you can also use .ChildAdded, but then you have to keep track of .ChildChanged, '.ChildRemoved', and .ChildMoved, which can get pretty complicated.

The FirebaseUI library for iOS handles this pretty easily.

dataSource = FirebaseTableViewDataSource(ref: self.firebaseRef, cellReuseIdentifier: "<YOUR-REUSE-IDENTIFIER>", view: self.tableView)

dataSource.populateCellWithBlock { (cell: UITableViewCell, obj: NSObject) -> Void in
  let snap = obj as! FDataSnapshot

  // Populate cell as you see fit, like as below
  cell.textLabel?.text = snap.key as String
}

Upvotes: 8

Related Questions