Beware Visitors Bearing Tints

TL;DR — Set your tint colors explicitly if you have many peer views, and dupe this:

rdar://26227380 UITintColorVisitor causes exponentially worsening performance when adding subviews

When adding subviews to a view that obtains its tint color from the window or a parent view performance gets exponentially worse the more subviews you add. When adding 6000 subviews execution takes over 10 minutes in the following method chain…

If you want a most excellent walkthrough of how to identify that kind of problem in object code, check out

Investigating the Cause of Quadratic Time Complexity When Adding Subviews in UIKit

We like our custom tint color; but not enough to justify such an impact on performance. By deactivating the custom tint color we bring the overall run time of viewDidAppear from our example project from over 700ms down to ~10ms…

The walkthrough of zeroing in on said cause goes through identifying the culprit with the time profiler down to sleuthing through its assembly and ending up as a practical tutorial in the use of Hopper Disassembler (which you may remember us mentioning Mike Ash’s posts on ages ago; also see Hopper + lldb for iOS Developers: A Gentle Introduction) to provide pseudocode for object code you don’t own, concluding

When I started out diving into this issue I was almost entirely clueless about how to interpret complex disassembled code – now I’m still mostly clueless. However, I learned a few very handy tricks along the way:

I learned how to set breakpoints in private methods & and at any address within the assembly code.

I learned about the i386 and Objective-C calling conventions, e.g. which arguments are stored in which registers.

I learned that the addresses in Hopper match the addresses in the actual framework code (besides a base pointers offset depending on where UIKit is loaded into memory). In hindsight this sounds obvious but it definitely was not the case when starting out. This article was very helpful in getting more comfortable with working with lldb in UIKit alongside of Hopper.

These three tools allowed me to explore the code paths & relevant variables a lot faster which in turn made it a lot easier (yet still hard) to get a grasp of what was going on.

In the end I didn’t find a definite answer on how this issue could be fixed, but I found a lot of clues about how the current visitor pattern is implemented and I think I got fairly close to the underlying issue.

Most importantly I learned how to be more efficient at exploring the inner workings of closed source frameworks which will surely come in handy in future!

Yes, that’s a bag of tricks definitely worth adding to your toolkit!

h/t: @jesse_squires, Michael Tsai!

Alex | May 13, 2016

Leave a Reply