0

My code below presents a view controller programmatically upon the user touch of a row in a table view. The code resides in 'didSelectRowtIndex' path and the table view resides in a ViewController class, where I've implemented table view delegates. The problem I'm having is that the view controllers I'm trying to present only appear on the second touch of the table view row. However when the parent view controller first loads, they appear on the first touch. Below is the code in 'didSelectRowAtIndexPath' for the presentation of the two of the child view controllers:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    if indexPath.row == 0 {

        let stockTable = StockTableVC()
        self.present(stockTable, animated: false, completion: nil)
    }

    else indexPath.row == 1 {

        let accountTable = AccountTableVC()
        self.present(accountTable, animated: false, completion: nil)
    }

    ...

Both present view controller methods above are being called every time upon row selection, but somtimes aren't presenting on the first selection (or at least they are not visible). Any help with this mystery would be great.

-Thanks

Hamish
  • 69,859
  • 16
  • 167
  • 245
jdeckman
  • 119
  • 10

2 Answers2

1

You have to deselect the row first. Add this before presenting:

tableView.deselectRow(at: indexPath, animated: false)

It's also a mistery to me, indeed. But this helped me to get it work while ago, I hope it works for you too.

Juan Curti
  • 2,794
  • 18
  • 35
  • Wow, it works. Thank you very much! I don't think I had this problem in earlier versions of Swift, but I may be wrong. – jdeckman Feb 15 '17 at 19:55
  • I'm not sure if this is something of Swift 3, but it happened to me a lot of times. Mark it as correct so that everyone can learn that this fixes it – Juan Curti Feb 15 '17 at 19:57
  • Thanks. I had to StackOverflow how to mark as correct. It's not very obvious. – jdeckman Feb 15 '17 at 20:02
0

Use my delay function (documented here):

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if indexPath.row == 0 {
        let stockTable = StockTableVC()
        delay(0.1) {
            self.present(stockTable, animated: false, completion: nil)
        }
    }
    // ... and so on ...
}

This gives the selection process time to finish before you start the presentation.

Community
  • 1
  • 1
matt
  • 447,615
  • 74
  • 748
  • 977
  • Interesting. Thanks, the deselect row solution above works fine but I'll try the latter if I have problems. – jdeckman Feb 15 '17 at 20:23
  • And what if the delay takes more than 0.1? The app will crash. Why is most recomended using this than deselecting the row? – Juan Curti Feb 15 '17 at 20:36
  • 1
    @JuanCurti It's not about the timing; it's about the threading. Thus, even a shorter delay will reliably work. The technique I'm using here is that we are exiting the main thread and allowing the runloop to complete, and coming back on the main thread in the next runloop. We are _guaranteed_ that the method we are in — `didSelect` — will have completed and the whole calling stack will have finished, since until that happens we won't be able to get back onto the main thread. And at that point, and _only_ at that point, we are safe to begin the presentation. – matt Feb 15 '17 at 21:48