I usually see RunLoop.current.run(until: Date())
called in integration tests.
For example in this article and in this open source project.
The explanation given in the article is
The RunLoop.current.run(until: Date()) statement makes sure the run loop associated with the current thread has ample time to let the drawing operations to complete
If that is true why wouldn't we give it more time, how do we know that Date()
is enough?
I read a few articles about the run loop and it seems to me like the reason that line of code is added is to start the app. It seems like the appDelegate usually automatically triggers or starts the run loop, but since we are testing we need to trigger the run loop ourselves.
I might be missing some fundamental understand of threads or run loops but I hope that someone can give some insight.
If that is true why wouldn't we give it more time, how do we know that Date() is enough?
We know from experimentation, I suppose. A more “correct” way to do it would be:
Date.distantFuture
).CFRunLoopStop(CFRunLoopGetMain())
when it detects that the views have been laid out and drawn.However, that's a lot of extra work to do instead of just RunLoop.current.run(until: Date())
, when the simpler method works and is unlikely to break.
I read a few articles about the run loop and it seems to me like the reason that line of code is added is to start the app. It seems like the appDelegate usually automatically triggers or starts the run loop, but since we are testing we need to trigger the run loop ourselves.
No, the app delegate does not start the run loop. The function UIApplicationMain
sets up the app and starts the run loop. If you create a new Objective-C project, you will find that the main
function in main.m
calls UIApplicationMain
. In a typical Swift project, the @UIApplicationMain
attribute attached to the app delegate tells the Swift compiler to generate equivalent code (a main
function that calls UIApplicationMain
) in AppDelegate.o
.
I might be missing some fundamental understand of threads or run loops but I hope that someone can give some insight.
An app spends most of its life in the run loop, which (simplified) has these phases:
needsLayout
property set, lay out the appropriate sections of the view hierarchy (which includes sending layoutSubviews
messages).needsDisplay
property set, draw those views (by sending drawRect:
messages).