Why does this code execute like this? Note the comments in the test code which indicate which lines pass and fail.
More specifically, how is it that RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.01))
waits there, while still allowing for the DispatchWorkItem
, { [weak self] in self?.name = newName }
, to process? If the thread is waiting on the run loop, how can the thread process any work items?
(Or please correct my understanding if the question doesn't make sense).
class Person {
private(set) var name: String = ""
func updateName(to newName: String) {
DispatchQueue.main.async { [weak self] in self?.name = newName }
}
}
class PersonTests: XCTestCase {
func testUpdateName() {
let sut = Person()
sut.updateName(to: "Bob")
XCTAssertEqual(sut.name, "Bob") // Fails: `sut.name` is still `""`
assertEventually { sut.name == "Bob" } // Passes
}
}
func assertEventually(
timeout: TimeInterval = 1,
assertion: () -> Bool
) {
let timeoutDate = Date(timeIntervalSinceNow: timeout)
while Date() < timeoutDate {
RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.01))
if assertion() == true { return }
}
XCTFail()
}