0

I have a very simple installTapOnBus closure that successfully updates the console, but not the UI element. Here's the code:

self.meter.text="..."
let inputNode = audioEngine.inputNode
let bus = 0

inputNode!.installTapOnBus(bus, bufferSize: 2048, format: inputNode!.inputFormatForBus(bus)) {
    (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
        var someFeature:Float=0.0
        for var i=0; i<Int(buffer.frameLength); i += 1{
           someFeature += fabs(buffer.floatChannelData.memory[i])
        }
        someFeature /= Float(buffer.frameLength)
        self.meter.text="\(someFeature)" // No effect!
        print("\(someFeature)") // This works
    }

Perhaps I need to send a weak reference to self to the closure, but am unsure of the syntax. Any feedback/ideas on how to get the UI element updating would be great! Thanks for reading.

Rogare
  • 3,104
  • 3
  • 24
  • 43

2 Answers2

1

The solution appears to be calling self.meter.text = ... on the main thread:

dispatch_async(dispatch_get_main_queue()) { 
    self.meter.text="\(someFeature)"
}

I'll leave this answer unchecked for a day or two, in case someone can fill out any more details on this.

Rogare
  • 3,104
  • 3
  • 24
  • 43
1

You should only make UIKit calls from the main thread.

From UIView's documentation:

Threading Considerations

Manipulations to your application’s user interface must occur on the main thread. Thus, you should always call the methods of the UIView class from code running in the main thread of your application. The only time this may not be strictly necessary is when creating the view object itself but all other manipulations should occur on the main thread.

If you look at the API reference for AVAudioNode and specifically installTapOnBus:

The tapBlock may be invoked on a thread other than the main thread.

Your UI was not updating because the callback from inputNode!.installTapOnBus() was executing on a background thread and you were then trying to update the UI from this thread.

As you have discovered, you will want to make your UI calls from the main thread via:

dispatch_async(dispatch_get_main_queue(), ^{
   /* Make UIKit calls here */
});
Community
  • 1
  • 1
Mark
  • 304
  • 2
  • 11