I’m having some compilation warnings using Xcode 14.2/swift 5.7 (future errors in swift 6).
I’ve some async function tests in a unit test target which include some code to process UI changes in the main loop.
There are two related warnings:
RunLoop.current.run(until: Date())
// which raises next warning
Class property 'current' is unavailable from asynchronous contexts; currentRunLoop cannot be used from async contexts.; this is an error in Swift 6
CFRunLoopRunInMode(CFRunLoopMode.defaultMode, 0.1, false)
// which raises next warning
Global function 'CFRunLoopRunInMode' is unavailable from asynchronous contexts; CFRunLoopRunInMode cannot be used from async contexts.; this is an error in Swift 6
Here a full function test example.
@MainActor
public class MainViewController: UIViewController {
...
public func showLoading() {
}
...
}
...
@MainActor
func testBasic() async throws {
// GIVEN
sut = MainViewController(nibName: nil, bundle: nil)
present(viewController: sut)
// WHEN
sut.loadViewIfNeeded()
sut.showLoading()
RunLoop.current.run(until: Date())
sut.hideLoading()
sut.showNoConnection()
RunLoop.current.run(until: Date())
// THEN
XCTAssertTrue(sut.connectionStatus.isHidden == false)
}
What alternatives would you use at this point to fix the warnings?
Extended question with more details
I understand that swift concurrency actors/Tasks are not in the same conceptual world than Runloops/Threads.
What I would expect to be able to do is to replace the Runloop code with something equivalent to
RunLoop.current.run(until: Date())
but in Tasks/Actors world.
await MainActor.run(forInterval: 0.1)
Or even better, what I would really like to achieve is to replace that piece of code (that Runloop snippet that I’ve copycat from some people unit tests code) that tries to force UI events processing.
2
Answers
So far, my understanding is that Runloop methods have been declared not async safe (which is understandable as it's Thread based), but without adding an async alternative so far.
So, at the moment, there are no fixes to this warnings, and instead it would be needed to avoid using Runloops in async contexts.
PD: This question was crossposted in an Apple forum post named How to adapt RunLoop to swift concurrency(async/await)
Just wrap
RunLoop.current.run(until: Date())
into a function:Then you can use
runCurrentLoop
in asynchronous contexts without warnings.