nontomatic nontomatic - 2 months ago 14
Swift Question

Reloading row in table view is delayed inadvertently

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!

Answer

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() 
    })
}