Last time I encountered this issue, it was hard to find the reason. We don’t know much about what actually UI Tests system waits for in such cases. There are rumours over internet that activity on main thread is what it looks for, but it’s not always the case. Let’s go over few tips that may help.
This one would help if activity on Main Thread prevents app from becoming idle. Even though it’s not always the reason, it probably counts for majority of cases. Just select the region of activity that you expect to be idle, and see all the unexpected calls. “Separate by Thread” Call Tree option may be helpful. Note that sometimes Main Thread is called Unnamed Thread for some reason.
Flash Updated Regions
If main thread is not the reason, next thing that comes to mind is Core Animation, which happens in a separate process. There are probably some Xcode Instruments that may highlight CA activity, but there is also another helpful Xcode feature: Xcode Menu > Debug > View Debugging > Flash Updated Regions.
Flash Updated Regions makes it easy to see what parts of your view are actually being updated.Apple doc
Option is available only when running on device, it is greyed out when running on device. Once enabled, iOS will blink yellow all the views being updated.
Watch out for “unfinished” animations
If animation is considered not completed, the app considered not idle. I don’t know how they track such stuff, maybe just an integer that increments when animation some animation API called
start(), and decrements when it’s asked
As an example, if you use
UIViewAnimating, and you use
fractionCompleted without ever stopping and finishing the animation, such animation will be considered active, even if fractionCompleted is set to 1.0.
The doc on fractionCompleted says:
You can update the value of this property only while the animator is paused.
Th doc on pauseAnimation() says:
Calling this method on an inactive animator moves its state to
UIViewAnimatingState.active… It is a programmer error to call this method while the state of the animator is set to
So if you want animator’s ability to scrub animation and still expect app to idle, you’ll probably need some tricky hack to achieve that.