0

When selecting a cell in the tableView I need to reload that row as well as setup some timers to fire AVAudioPlayers at certain dates (this setup takes a few seconds, the timers are starting to firing already, though, as intended).

However, reloading the table view row (which effectively highlights the row) is delayed for a few moments.

I need the row to reload as the first thing when selecting the to preserve a good UI experience.

I've tried to put the reload part in the main thread, as suggested here: UITableView reloadData() gets fired but delays

This won't work for some reason:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
  // do some things

  dispatch_async(dispatch_get_main_queue(), {
    tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
  })

  setupTimersToFireAtDate() 
}

func setupTimersToFireAtDate() {
  let start = NSDate()
  // These are Float as they will be calculated with other Float values
  var accumulatedTime: Float = 0.0
  var elapsedTime: Float = 0.0

  for event in events {
    var player = AVAudioPlayer()
    accumulatedTime += event.time

    do {
      // the urls array keeps urls to the sounds. For this example, I've set the index to be random, since it doesn't really matter.
      player = try AVAudioPlayer(contentsOfURL: urls[Int.random])
      // Players need to be maintained in order to playback, each player is removed with the audioPlayerDidFinishPlaying AVAudioPlayerDelegate method.
      players += [player]
    } catch let error as NSError {
      loadError = error
    }

    elapsedTime = Float(NSDate().timeIntervalSinceDate(start))

    // Some other calculations in between here.

    player.prepareToPlay()
    player.delegate = self
    player.currentTime = 0.0

    player.playAtTime(player.deviceCurrentTime + (NSTimeInterval(accumulatedNoteTime - elapsedTime)))
  }
}

I may be missing something here, since I don't know why this isn't working.

Any help much appreciated!

Community
  • 1
  • 1
nontomatic
  • 2,003
  • 2
  • 24
  • 38
  • Update your question with your `setupTimersToFireAtDate`. Since all of that code is being done on the main thread, your call to `reloadRowsAtIndexPaths` won't run until `setupTimersToFireAtDate` completes. – rmaddy Oct 03 '16 at 21:42
  • Hi rmaddy, thank you for your comment. I have updated the code, but I have stripped down that method to the relevant parts. As you've said, these are on the main thread, the player timing is very important but I do need the row to update first, the user shouldn't wait 2 seconds to see the selected row highlight. – nontomatic Oct 03 '16 at 22:01

1 Answers1

1

The easiest solution is to delay the call to setupTimersToFireDate so the call to reloadRowsAtIndexPaths can run immediately.

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    // do some things

    tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)

    dispatch_async(dispatch_get_main_queue(), {
        setupTimersToFireAtDate() 
    })
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • I'll gladly take the easiest solution! It works great, thanks a lot, rmaddy. Turns out, I had dispatched the wrong part of it. – nontomatic Oct 03 '16 at 22:15