How we avoid threading issues by using Main Queue
How we avoid threading issues by using Main Queue
Sometimes the best solution a problem is to not solve it at all, this is even more true for programming. Multithreading is an aspect with many pitfalls. This is not just an issue of understanding multithreading and how it works but understanding how bugs creep up due to our unawareness about the working of underlying systems or hardwares.
But these issues don’t need to be tackled everytime. We can be simply avoid them if our constraints allows, more so with GCD where we can take advantage of queues to get our work done. We at NoctaCam try to keep most of our code in mainQueue and use many tricks to avoid using other queues. This is not to say that we compromise on performance or user experience but we realize we simply don’t need to. This post is all about how we do it.
First the advantages of having the code in main queue:
Debugging: This would be the single most important factor if one were to pick among all advantages of having single threaded code. Debugging is a breeze if the state and execution flow of the program can be easily predicted.
Faster Development: In a startup environment we need to build fast, push quickly and iterate. Multithreaded problems hold up the development speed and the release cycles.
Simpler Code: Anybody who’s written multithreaded code knows how much extra code is needed just to make it work correctly. Team members try to avoid working on code written by other members as locks and other synchronisation primitives make it hard to read and understand.
So how do we do it?
By taking advantage of GCD API as much as possible. By having all the code running in main queue doesn’t mean parallelism and performance is compromised. The bottle necks of the code can be written in a way that they are parallelised but don’t cripple other aspects of it. For example:
This is a version of map function which does its processing in parallel but returns the result synchronously giving you performance in critical aspects of your code.
For code that can be afforded to run asynchronously, don’t use a background queue, just submit it to main queue asynchronously. You can use this wrapper function:
Tasks which are to be done repeatedly in background throughout the execution of the program can also be done on main queue given that they are not long running like this:
Just submit the same task to mainQueue asynchronously with some delay repeatedly. This looks like recursion but it’s not as the updateUI function returns everytime after submitting itself to mainQueue.
NSNotifications and KVO calls need to be taken care of. One cannot rely on them being called on main queue. Also, there are several iOS methods whose callbacks are returned on some arbitrary background queue. So hop the call to main queue when the documentation says it’ll be on a background queue or is unclear.
Pitfalls
Ofcourse this is not a silver bullet, we needed to add some monitoring to log if any task is taking a long time which might block the main queue. The only rule that one needs to follow in working with main queue is that it shouldn’t be blocked in no circumstance. Which means any real time processing can not be done on main queue.