-2

I know the UI needs to be updated on the main thread.

I would simply like to understand what's going on behind the scenes that accounts for incredibly long delays in code that attempts to update the UI from a background thread.

Let's say your app's initial setup in terms of database calls is complete and your UITableView datasource array is fully populated. All view controllers and their subviews have been fully rendered. Your code is doing nothing but waiting for a user action. For good measure, you wait 30 seconds longer than you think is necessary in order to make sure of this.

You then do some user action that triggers a line of code that tries updating the UI on a background thread. The result is a full 2 or 3 second delay before the UI gets updated.

If a background thread amounts to a extra processor running in parallel with a main processor, and if that extra processor has exactly zero other code to run, what on earth is it doing for two full seconds, which is an eternity for executing a single line of code?

ClayJ
  • 377
  • 2
  • 14
  • You are correct and I will edit my question. I came to this erroneous conclusion because there is a bug in Apple's code when you present a view controller from didSelectRowAt(), and the workaround to that bug is to wrap the presentation of that view controller in DispatchQueue.main.async{}. See: https://stackoverflow.com/questions/21075540/presentviewcontrolleranimatedyes-view-will-not-appear-until-user-taps-again/30787046#30787046 – ClayJ Sep 10 '19 at 23:41
  • I don't believe in that "bug". – matt Sep 11 '19 at 02:56
  • A significantly more useful comment would be to explain why you don't believe in it. – ClayJ Sep 11 '19 at 04:06
  • Because I've been using `didSelect` for a decade in just about every app I write and I've never encountered an issue with it? – matt Sep 11 '19 at 04:48

1 Answers1

3

You've created a race condition. The system isn't doing anything; it doesn't know that it needs to update the display. As an example of the kind of race condition that occurs, you can easily get a situation like this:

  • (main) UI event happens
  • (main) Set "needs display"
  • (main) Runloop cycles around and sees "needs display"
  • (main) Runloop starts display update
  • (main) Make snapshot of all the things that need to updated and start working through them.
  • (background) Some event that leads to set "needs display"
  • (main) Finish list (doesn't include that background thing)
  • (main) Clear "needs display" (it's not a stack; it's just a bool and now it's "false")
  • (main) Runloop cycles around and sees nothing needs to be displayed. (Background thing got lost)
  • ...
  • ... 2 seconds, or whatever. It could be a really long time, or right away.
  • ...
  • (main) Something happens that sets "needs display"
  • (main) Now that thing that happened in the background gets drawn (if you're lucky)

This is probably the most benign version of the issue. UIKit is not thread-safe. Making random changes on the background can absolutely trash state and lead to all kinds of bizarre behaviors and crashes. If you're lucky, it'll just take awhile for your update to show up.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610