You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何适配RunLoop至Swift并发(async/await)?解决编译警告

替代RunLoop的异步测试UI刷新方案

方案1:使用await Task.yield()

Task.yield()会让当前异步任务暂停,让出主线程处理所有待执行的UI更新和主队列任务,是最贴合Swift Actors/Tasks体系的替代方式。

修改后的测试代码:

@MainActor
func testBasic() async throws {
    // GIVEN
    sut = MainViewController(nibName: nil, bundle: nil)
    present(viewController: sut)

    // WHEN
    sut.loadViewIfNeeded()
    sut.showLoading()
    await Task.yield() // 替代RunLoop.run,等待UI更新完成

    sut.hideLoading()
    sut.showNoConnection()
    await Task.yield() // 等待UI状态变更

    // THEN
    XCTAssertFalse(sut.connectionStatus.isHidden)
}

方案2:等待指定时长确保UI处理完成

如果UI更新涉及动画或延迟操作,Task.yield()可能无法满足需求,可结合Task.sleep(nanoseconds:)等待固定时长,确保UI渲染完成:

@MainActor
func testBasic() async throws {
    // GIVEN
    sut = MainViewController(nibName: nil, bundle: nil)
    present(viewController: sut)

    // WHEN
    sut.loadViewIfNeeded()
    sut.showLoading()
    // 等待0.1秒,确保UI渲染完成
    try await Task.sleep(nanoseconds: 100_000_000)
    await Task.yield()

    sut.hideLoading()
    sut.showNoConnection()
    try await Task.sleep(nanoseconds: 100_000_000)
    await Task.yield()

    // THEN
    XCTAssertFalse(sut.connectionStatus.isHidden)
}

方案3:自定义等待UI状态的工具函数

如果需要等待特定UI状态变为预期值,可编写异步轮询函数,避免固定等待时长的不确定性:

@MainActor
func waitUntil(_ condition: @escaping () -> Bool, timeout: TimeInterval = 1) async throws {
    let startTime = Date()
    while !condition() {
        if Date().timeIntervalSince(startTime) > timeout {
            throw XCTestError("等待UI状态超时")
        }
        await Task.yield()
    }
}

// 测试中使用
@MainActor
func testBasic() async throws {
    // GIVEN
    sut = MainViewController(nibName: nil, bundle: nil)
    present(viewController: sut)

    // WHEN
    sut.loadViewIfNeeded()
    sut.showLoading()
    await waitUntil { sut.loadingIndicator.isHidden == false }

    sut.hideLoading()
    sut.showNoConnection()
    await waitUntil { sut.connectionStatus.isHidden == false }

    // THEN
    XCTAssertFalse(sut.connectionStatus.isHidden)
}

关键说明

  • 所有方案均在@MainActor上下文执行,确保UI操作和状态检查都在主线程
  • Task.yield()是Swift异步体系中让出执行权的标准方式,可替代RunLoop手动运行逻辑,适配Swift 6的异步上下文规则
  • 避免使用RunLoop/CFRunLoop相关API,消除编译警告并兼容未来Swift版本

内容的提问来源于stack exchange,提问作者kikeenrique

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 08:55:21