1

Calling tableView.reloadData() seems to initiate the reload on a different thread. If I immediately try to select a cell I've added to my data structure, it may not have been reloaded by the TableView yet. Is there a way to tell when the TableView has completed the reloadData() process. My actual code is:

DispatchQueue.main.async {
        self.tableView.reloadData()
        self.selectNode(node: newNode)
    }

Where selectNode is my function to locate the TableViewCell displaying that node. Frequently, it fails because TableView hasn't re-displayed it yet. I can "brute force" a solution by inserting a wait loop that checks to see if TableView has requested all my rows since the reload, but I had hoped there was a more elegant solution. I'm also uncomfortable with wait loops in general.

jralden
  • 75
  • 1
  • 8
  • You may want to run reloadData() on the main thread which I believe is the best practice - `DispatchQueue.main.async { self.tableView.reloadData() }`. That will help avoid the race condition you're running into. – Marcus Leon Mar 14 '17 at 21:18
  • reloadData() doesn't work on a background thread (assuming you're calling it on the main thread, which you should always do). It's done as soon as the call returns; there's nothing else you need to do. Maybe your issue is that only the visible rows are reloaded? See [the reference](https://developer.apple.com/reference/uikit/uitableview/1614862-reloaddata). – zpasternack Mar 20 '17 at 07:51
  • As you can see from my code, I am calling it on the main thread, and also attempting to select a cell on the main thread afterwards. I am managing row selection myself. I'm calling reloadData because I've just added a new item near the bottom of the table and want to select it. The select method fails because the cell hasn't been reloaded yet immediately after the call. So, empirically, I would have to say reloadData appears not to be running on the main thread. Print statements in tableView cellForRowAt: confirms that it seems to continue well after it returns from the reloadData call – jralden Mar 21 '17 at 14:26

1 Answers1

0

I wanted to share the solution I found to the problem, as well as what it implies about how tableView.reloadData works. First, here's the code that I finally arrived at that works:

func addNewItem() {
    // here we create the kind of item the user chose

    //ending with this 
    tableView.reloadData()
    queueCheckForDone()
}

func queueCheckForDone() {
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .milliseconds(1), execute: {
        self.checkForDone()
    })
}

func checkForDone() {
    if items[items.count-1].viewCell != nil {     // has last view cell been created
        self.selectItem(item: addedItem)
    } else {
        queueCheckForDone()
    }
}

The issue was that immediately after the reloadData, I wished to select the cell that I had just been added. But, it wasn't there immediately after the call, because the tableView hadn't finished loading. reloadData wants to run on the main thread, and my code, an event handler, was blocking it by being on the main thread. As soon as I relinquished the thread to wait, for even a millisecond, reloadData seized the thread and reloaded the whole table(> 250ms). When I finally got control again, the cell I was looking for was always there, and so I never executed the else clause of the checkForDone test.

jralden
  • 75
  • 1
  • 8