Background: Apple is somewhat clear about developers sticking to main thread context when calling UIKit related interfaces. The following is from Apple documentation as of 10/1/2016.
somewhat clear but not fully clear based on "For the most part" in the above quote. The reason is that graphic updates to the apps graphic buffers have to be synchronized.
Why don't UIKit calls fail if made from background thread? It doesn't make sense for Apple to enforce this rule for each and every UIKit interface without getting hit with a performance penalty. So the UIKit interfaces just assume that the call is being made from the main thread. If the call is being made from a background thread, the results are unpredictable and its the developers(and the poor QA's) cross to bear for not following Apple's rules.
Why can't Apple support catching UIKit background thread access at runtime in debug mode? Good question. It will be great if they can support catching UIKit background use in the Instruments tool. This will be useful for developers since purely based on personal experience, I have seen this UIKit rule being broken in all projects I have worked on. So I am guessing that this is a common problem. The worst part is that its very hard to figure out that this is the underlying cause for inconsistent app behavior reported by QA.
How to solve this problem? Its easier to find a technical fix for this issue rather than trying to fix the developer. Our technical fix doesn't really fix the problem as such but it points out code which is using UIKit methods from background thread. This will at least alert the developer about the location of problem pieces of code. Nothing alerts a developer more than a clear assert in code. So what we will attempt to do here is to catch the background usage of UIKit and throw an assert in the same thread context. The Xcode debugger will display the call stack of the thread which asserted and will help the developer locate the problem code.
Requirements for the solution.
- To make the solution easy usable, it should be minimally invasive. A single file if possible.
- It should support enable/disable at runtime. This is really important since the app may have the issue in multiple places and each piece can be tested by the responsible engineer separately by enabling UIKIt usage tracking for that part.
- It should be Swift compatible
We will assume that the following commonly invoked UIKit interfaces does manipulate our app's user interfaces.
Outline of a solution: Imagine that we somehow manage to override the above two methods for all UIView instances in the app. In our override, we check if the method is being called from main thread. If it is, then call the default implementation. If its not, ASSERT!
How to override methods of system classes?
Author: Raj Lokanath