For iOS apps, UI updating is done from the main thread exclusively - not doing so is never recommended and can lead to unexpected behaviour.
In watchOS, the OS is structured with a watch extension, and an app - as different 'containers'. Usually, UI updates are called from the extension, and these update something in the app's container.
Does the same main thread logic apply to updating UI from the watch extension, or can UI updates be called from the background?
Edit - to bring some clarity. From the app's container, UI updates should probably happen on the main thread (as happens in most systems/OSs, as pointed out below). The question is really whether watchOS handles that for us, i.e. whether calling a UI update on the background thread of the extension will automatically be posted to the main thread of the app's container for us.
After contacting Apple through a Technical Support Incident, the received answer and explanation is below.
TLDR: use the main thread.
All updates should be done from the main thread. This has always been the general recommendation for UIKit and that recommendation extends to watchOS.
It might be helpful to understand the underlying reason for this requirement. Keep in mind that, even with a centralized communication channel to serialize changes, many problems arise when you attempt to manipulate UI state from background threads. For example, while the serialization channel can prevent multiple UI commands from attempting to simultaneously execute, it can’t control the order in which unrelated commands will execute. Consider the following 2 blocks:
block 1 { DoUIChange1 DoUIChange2 } block 2 { DoUIChange3 DoUIChange4 }
If both blocks are executed on the main thread, then the actual command stream is either:
DoUIChange1 DoUIChange2 DoUIChange3 DoUIChange4
or…
DoUIChange3 DoUIChange4 DoUIChange1 DoUIChange2
However, if both blocks are executed on their own threads, even more possibilities open up:
DoUIChange3 DoUIChange1 DoUIChange2 DoUIChange4
or..
DoUIChange1 DoUIChange3 DoUIChange2 DoUIChange4
or..
DoUIChange1 DoUIChange3 DoUIChange4 DoUIChange2
etc…
Needless to say, if the UI code is at all complex the number of combinations quickly becomes enormous, making unexpected UI bugs basically unavoidable.