1

I am creating a swift app with AVFoundation and using an AVAudioPlayerNode. I disable the play button while playing and in the completion portion of the player I enable it, but the button stays transparent for over 10 seconds. The button is useable and my print("complete") shows immediately, so it seems like the view is not updating. Here is my code:

player.scheduleBuffer(buffer, completionHandler: {              
            print("complete")
            self.playButton.enabled = true
            }
        )

I have tried the following with no luck:

self.view.layoutIfNeeded()
player.scheduleBuffer(buffer, completionHandler: {
            print("complete")
            self.playButton.enabled = true
            self.playButton.reloadInputViews()
            self.view.layoutIfNeeded()
            }
        )
  • One of the many duplicates: http://stackoverflow.com/questions/32296295/uiimageviews-image-takes-up-to-10-seconds-to-load – Sulthan Dec 28 '15 at 19:42

2 Answers2

2

That is probably because the completion handler is not called on the main thread which is responsible for updating UI.

Check if the completion handler is running on the main thread if not then add code responsible for updating UI on the main thread

For quick check of the reason why UI is not updated immediately try this, place the code in completion handler additionally in :

NSOperationQueue.mainQueue().addOperationWithBlock({
       print("complete")
        self.playButton.enabled = true
        self.playButton.reloadInputViews()
        self.view.layoutIfNeeded()
    })

Checking if code is running on the main thread can be done in swift like:

print(NSThread.isMainThread())

I assume you placed layoutIfNeeded while looking for the solution, without bigger context I can not say with 100% sure but probably you won't need it

Julian
  • 9,299
  • 5
  • 48
  • 65
  • I tried calling a main thread function from the completion handler, but that did not help. –  Dec 28 '15 at 19:39
  • player.scheduleBuffer(buffer, completionHandler: { print("complete") completion() } ) –  Dec 28 '15 at 19:40
  • updated answer, but all you ask now are very basic issues, you should search them over the web – Julian Dec 28 '15 at 19:50
  • This is a better explanation than the selected answer. You might want to point out that NSOperationQueue is a high level abstraction that uses Grand Central Dispatch under the hood. +1 – Dan Beaulieu Dec 28 '15 at 19:57
  • @DanBeaulieu thanks that you appreciate. Yes, I used that API as it is higher level API than GCD moreover I find more readable and modern :) – Julian Dec 28 '15 at 20:00
1

The completion handler is not in the main thread. You can move that portion of the code by using this code:

self.player.scheduleBuffer(buffer, completionHandler: {

    print("complete")

    dispatch_async(dispatch_get_main_queue(),{
    self.playButton.enabled = true
    })
})
user4812000
  • 1,033
  • 1
  • 13
  • 24