Are Multiple UI Threads Possible?

I've got a potential scenario where it may be ideal to have multiple UI threads.

I have an iOS application which presents unrelated content on multiple separte screens/windows. Each window may be reasonably intensive on a single thread so running multiple windows at a time, all on the same UI thread, would result in bad performance.

Is it possible to have effectively multiple ui threads - one for each window - in iOS? Or is there a similar, but different solution, to this?


Thanks!

Replies

>> Each window may be reasonably intensive on a single thread


What does that mean, exactly? If the main thread is busy with UI activity for the window (for example, if you're creating and deleting lots of views in a short time, or if your UI has thousands of views) then you should redesign your app to use a different approach. Or, if the main thread is busy preparing data from display in the windows, then you should start using an async pattern, where you move the data preparation into the background (ideally using dispatch queues or NSOperation queues), presenting it back to the main thread when it's ready.


There's really no good reason (that I can think of) for a well-designed app to keep the main thread very busy.


To answer your specific question, there aren't really any "UI threads". There's the main thread/queue (one only) and background threads/queues (as many as you want). There are some background drawing capabilities, such as:


developer.apple.com/reference/quartzcore/calayer/1410974-drawsasynchronously


but Apple recommends against their use. Another general approach is to use OpenGL to replace a view hierarchy, but the feasibility depends on what you're displaying.

So, more specifics about exactly what I'm looking to do is.

I have a graph/chart heavy application. Those graphs/charts are intensive to render and are animated - hence they load the thread they are running on pretty well.

I need to be able to render multiple sets of charts in different confugrations and ultimately be able to stream it in video form over the internet.

It's almost like effectively running two separte iOS apps simultaneously - and streaming the view of one of them.

The application has been under development for a few years and was not originally designed to render multiple scenes at the same time.

So the simplest approach I can think of, is if it were possible to be able to render each scene on a different thread.

And since these scenes are composed of UIViews, with a mix of autolayout, drawRect, etc. Having another fully functional UI thread would be ideal for minimal refactoring/redesign time.

The UI performance is currently fine when only running a single scene. But at full interaction with animations and all kinds of stuff, the main thread is over 50% utilized - so doubling the load on the same thread (with another scene) results in less than acceptable results.

It's not my area of expertise, but for graphics-intensive rendering, you should probably move into Core Animation (layers and animations) instead of working directly with views. That should allow you do some rendering on background threads.

I was going to suggest Apple's Concurrency Programming Guide but it isn't swift and hasn't been updated in some time, so... (feel free to laugh if you get the hi tech humor)

Let's be plain about it: UIKit (which basically cover all of the "UI Thread" territory) isn't thread safe and the things that draw the view hierarchy run on the main thread. The rare exceptions are outstanding enough that they get mentioned explicitly in the documentation as being thread safe or being designed to run in another thread/queue.


On the other hand, it really depends on what you're doing and what sorts of latency you're allowing for how much you can offload to another thread. Because the straight forward way of offloading things that were originally done on the main thread to a background thread ends up looking a lot like this:


  • You've got an action method that's responding to the user tapping a button. Gather up all of the relevant parameters and dispatch a block to the worker queue.

    Inside that worker block, do the computation and work. Gather up the relevant results and dispatch a block to the main queue.

    • Inside this second block, use the passed in results to update the user interface.
    • Sometimes, the worker block ends up dispatching multiple blocks to update the user interface. This is okay.
  • Make any UI updates for the action method that either don't have to wait for the worker block, or that get things ready for the worker block. For example, do you need to disable a button or display a "Please wait" message?


Where it gets tricky is dealing with worker blocks that have become irrelevant. And you have to be careful that you don't end up making the app feel slower because of how long it takes your worker block to do the work before you update your UI.

I understand that UIKit is not designed to be thread safe, and that generally long running tasks need to be offloaded to other threads to avoid blocking the main thread.

I'm just currently making UIKit do a lot of work - animations, autolayout etc. Which cannot be offloaded to another thread - therefore being a prime candidate for the creation of another UI thread and everything that goes along with that.


So what I want is sounding to be unlikely.

I want to be able to duplicate my application into another window and have the second window not interfere with performance of the main window.

Without significant rewriting effort.


Another UI thread working on the separate window would solve my problem immediately and gracefully.


I do appreciate all of the comments though.

So, thank you.