0

I'm creating a Swift Firebase app with a TableViewController where each section of the tableview is a room and every row is the furniture of each room.

Now to the problem: The first time it loads everything works fine and when any of the rooms are getting changed/removed from the backend the table view update just fine. But I have a problem getting the data to reload when any of my furniture values updates. I have no idea how to change my code to get this working. I'm starting thinking I might be using an incorrect structure of my data? How can I fix this issue?

The structure of the Firebase database is this (I removed some keys/values from the structure just to simplify so the real structure has more values):

rooms:
{
    "room 1": {
        "name": "Bedroom",
        "somedata": 1
    },
    "room 2": {
        "name": "Living room",
        "somedata": 2
    }
}

furniture:
{
    "room 1": {
        "furniture 2": {
            "name": "Chair"
        },
        "furniture 3": {
            "name": "Sofa"
        }
    },
    "room 2": {
        "furniture 1": {
            "name": "Table"
        }
    }
}

The code I use to load the data in the TableViewController is:

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

    DataManager.shared.getRooms(completion: { (rooms) in
        self.rooms = rooms
        self.tableView.reloadData()
    })
}

DataManager:

func getRooms(completion:@escaping ([Room])->Void) {
    FIRDatabase.database().reference(withPath: "rooms").observe(.value, with: { snapshot in
        var rooms: [Room] = []
        var counter: UInt = 0
        for roomItem in snapshot.children {
            let room = Room(snapshot: roomItem as! FIRDataSnapshot)
            FIRDatabase.database().reference(withPath: "furniture/\(room.key)").observe(.value, with: { snap in
                for furnitureItem in snap.children {
                    let furniture = Furniture(snapshot: furnitureItem as! FIRDataSnapshot)
                    room.furnitureList.append(furniture)
                }

                counter = counter + 1
                if (counter == snapshot.childrenCount) {
                    completion(rooms)
                }
            })

            rooms.append(room)
        }
    })
}

Thanks for helping!

Martin
  • 7,190
  • 9
  • 40
  • 48
  • Going to take a stab at it here, maybe try wrapping the completion call back in a dispatch async? – TNguyen Jun 13 '17 at 20:54
  • I think it shouldn't be needed? Please see comment below – Martin Jun 14 '17 at 08:28
  • hmm, it's hard to pin point the problem only being able to see that much. Can you maybe try double checking to see if your callback is being called after you change a furniture? – TNguyen Jun 14 '17 at 15:36

1 Answers1

0

You need to call self.tableView.reloadData() like so:

DispatchQueue.main.async {
    self.tableView.reloadData()
}

Also, no need to call the function in viewDidAppear. Call it in viewDidLoad.

Archie Gertsman
  • 1,601
  • 2
  • 17
  • 45
  • Thanks a lot! From my understanding you don't need to use DispatchQueue as this is already happening on the main thread, at least according to this post: https://stackoverflow.com/questions/39178165/firebase-asynchronous-function-whats-in-the-background-queue-and-whats-not – Martin Jun 14 '17 at 08:27
  • I put it in viewWillAppear because if this blog post https://firebase.googleblog.com/2015/10/best-practices-for-ios-uiviewcontroller_6.html) it says “Create listeners in viewWillAppear, not in viewDidLoad”. Isn’t that correct? – Martin Jun 14 '17 at 08:27
  • Regarding where to observe: https://stackoverflow.com/questions/37895171/new-firebase-retrieve-data-and-put-on-the-tableview-swift – Archie Gertsman Jun 14 '17 at 17:58