Threading issue? audioRequested does not update iOS UI

Hi folks,

Have run into an odd problem:

I have a nice, accurate timer running, based on audioRequested (see this thread: accurate sequencing) and it kicks my metronomeClick method nicely.

But if I try to use metronomeClick to update anything in my iOS UI then the UI refuses to update. I’m just trying to do basic things like flash a UIImageView on and off using its setHidden property, but although I can set the property, there is no change on the screen.

If I try to change the setHidden property via an event from somewhere else (not the metronome) e.g. a touch event, then the UIImageView behaves fine.

In both cases (the touch event, and the metronome event) the same methods are used to hide/show.

I have tested it using a nib-based view and a programmatic view - no difference.

I have tried using NSNotification to call the update - no difference.

I have tried adding a setNeedsDisplay on the view to force a drawing update - no difference.

I can see that the metronome does correctly set any underlying values, but nothing gets updated on the screen.

My only thought is that there’s something inherent in the audioRequested threadness which is blocking the UI updating… but unsure how to test further…

Anyone seen something like this before? Any suggestions for further debugging?

This is because audioRequested is going to be called on the audio thread, which is separate from the main thread (where all UI things need to happen).

A relatively straightforward way to get around this is to wrap any UI calls from audioRequested with a dispatch_async call like this:

dispatch_async(dispatch_get_main_queue(), ^{
    [UIWhatever doTheThing];
1 Like

@admsyn You, sir, have just made me a very happy man. That works! Finally - after hours of head-scratching and googling. Many, many thanks.

I do have a follow-up question though, just so I understand it a bit better…

I have the main drawing done using OF calls and basically running from the main thread’s draw method. The UI where I was having problems is not done there, but in an iOS UIView which is created by the main’s setup, but overlaid and then left to handle events/drawing by itself. The audioRequested tick updated the coordinates for both the main drawing and the appearance for the UIView, but (until I used your dispatch_async) only the former updated properly.

My question is: shouldn’t both of them (main drawing and UIView) be inside the main thread and neither of them should’ve been updated by the audio thread? It looked like half of it was being updated and half not. Any tips to understanding what was going on greatly appreciated. Cheers :smile:

Yeah, anything working directly with UIKit should be on the main thread, though sometimes if you slip up and do stuff on a separate thread things will kinda-sorta-work. You most definitely shouldn’t depend on anything working if you’re calling it on a separate thread and it’s not documented to be safe to use that way :slight_smile:

Note that openFrameworks’ draw() & update() are going to be on the main thread too, so they’re on the same thread as your regular UIView. The fact that one worked and the other didn’t is probably just an implementation quirk in UIKit.

Makes sense… thanks for the explanation…