我通常会在集成测试中看到RunLoop.current.run(until: Date())
调用。
例如,在本文中和此开源项目中。
文章中给出的解释是
RunLoop.current.run(until: Date((( 语句确保与当前线程关联的运行循环有足够的时间让绘制操作完成
如果这是真的,我们为什么不给它更多的时间,我们怎么知道Date()
就足够了?
我读了几篇关于运行循环的文章,在我看来,添加代码行的原因是启动应用程序。似乎 appDelegate 通常会自动触发或启动运行循环,但由于我们正在测试,我们需要自己触发运行循环。
我可能缺少一些对线程或运行循环的基本理解,但我希望有人能给出一些见解。
如果这是真的,我们为什么不给它更多的时间,我们怎么知道 Date(( 就足够了?
我想,我们从实验中知道。一个更"正确"的方法是:
- 安装一个运行循环观察器,以某种方式检测视图何时被布置和绘制。
- 无限期运行运行循环(直到
Date.distantFuture
年(。 - 在步骤 1 中安装的观察程序中,当它检测到视图已布局和绘制时调用
CFRunLoopStop(CFRunLoopGetMain())
。
然而,当更简单的方法起作用并且不太可能中断时,这需要做很多额外的工作,而不仅仅是RunLoop.current.run(until: Date())
。
我读了几篇关于运行循环的文章,在我看来,添加代码行的原因是启动应用程序。似乎 appDelegate 通常会自动触发或启动运行循环,但由于我们正在测试,我们需要自己触发运行循环。
否,应用委托不会启动运行循环。该函数UIApplicationMain
设置应用并启动运行循环。如果你创建一个新的Objective-C项目,你会发现main.m
中的main
函数调用UIApplicationMain
。在典型的 Swift 项目中,附加到应用程序委托的@UIApplicationMain
属性告诉 Swift 编译器生成等效代码(调用AppDelegate.o
UIApplicationMain
的main
函数(。
我可能缺少一些对线程或运行循环的基本理解,但我希望有人能给出一些见解。
应用的大部分生命周期都在运行循环中度过,运行循环(简化(具有以下阶段:
- 等待事件。 有很多事件源,包括应用程序启动、触摸、计时器、加速度计、GPS、进入后台、返回前台等。
- 处理事件,通常通过调用您编写的代码。
- 如果任何视图设置了
needsLayout
属性,请布置视图层次结构的相应部分(包括发送layoutSubviews
消息(。 - 如果任何视图设置了
needsDisplay
属性,请绘制这些视图(通过发送drawRect:
消息(。 - 返回到步骤 1。