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

Swift中Spinner在队列任务完成前提前消失的问题求助

解决Spinner提前消失的异步队列问题

兄弟,我太懂这种被异步逻辑坑到抓狂的感觉了😅——你明明想等所有DCS BIOS的消息都发送完再把Spinner去掉,结果它早早消失,任务还在后台跑,完全不符合预期。

问题根源

你代码里的biosQueue.async { dcsBIOSConn.sendMessageQueueToDCSBIOS() }是非阻塞异步操作:当你把这个任务扔进biosQueue后,当前的utility队列不会等它执行完,直接跳过继续往下走,立刻就调用了DispatchQueue.main.async去移除Spinner。这就是为什么打印顺序是1→2→3,而发送消息的日志在最后才出现——Spinner的移除逻辑根本没等发送任务完成。

两种可行解决方案

方案一:用同步执行阻塞当前队列

把biosQueue.async改成biosQueue.sync,这样当前的utility队列会暂停,直到sendMessageQueueToDCSBIOS()完全执行完毕,再继续后续的主线程Spinner移除操作:

DispatchQueue.global(qos: .utility).async { [weak self] in 
    guard let self = self else { return } 
    switch airframe{ 
        case .A_10: 
            dcsBIOSConn.configureHawgWaypoint(name: name, lat: latitude!, long: longitude!, elev: elev, tot: timeOnTarget) 
        case .F_16, .F_18, .AV_8B: 
            dcsBIOSConn.configureWaypoint(lat: latitude!, long: longitude!, elev: elev, aircraft: airframe!) 
        default: break 
    } 
    dcsBIOSConn.printMessageQueue() 
    print("1. Entering Queue") 
    let biosQueue = DispatchQueue(label: "dcs_bios") 
    // 改成sync,让当前队列等待biosQueue的任务完成
    biosQueue.sync { 
        dcsBIOSConn.sendMessageQueueToDCSBIOS() 
        print("任务发送完成")
    } 
    print("2. Finishing Out of Loop") 
    // 此时发送任务已完成,再更新UI
    DispatchQueue.main.async { [weak self] in 
        self?.removeSpinner() 
        print("3. Remove Spinner") 
    } 
}

这种方案的打印顺序会变成:1→任务发送完成→2→3,完全符合你想要的“任务完成后再移除Spinner”的逻辑。

方案二:在发送任务内部调度主线程

如果不想阻塞utility队列(比如后续还有其他任务要执行),可以把移除Spinner的逻辑直接放到biosQueue.async的闭包末尾,等发送任务完成后再回到主线程更新UI:

DispatchQueue.global(qos: .utility).async { [weak self] in 
    guard let self = self else { return } 
    switch airframe{ 
        case .A_10: 
            dcsBIOSConn.configureHawgWaypoint(name: name, lat: latitude!, long: longitude!, elev: elev, tot: timeOnTarget) 
        case .F_16, .F_18, .AV_8B: 
            dcsBIOSConn.configureWaypoint(lat: latitude!, long: longitude!, elev: elev, aircraft: airframe!) 
        default: break 
    } 
    dcsBIOSConn.printMessageQueue() 
    print("1. Entering Queue") 
    let biosQueue = DispatchQueue(label: "dcs_bios") 
    biosQueue.async { 
        dcsBIOSConn.sendMessageQueueToDCSBIOS() 
        print("任务发送完成")
        // 发送完成后,直接调度主线程移除Spinner
        DispatchQueue.main.async { [weak self] in 
            self?.removeSpinner() 
            print("3. Remove Spinner") 
        } 
    } 
    print("2. Finishing Out of Loop") 
}

这种方案的打印顺序会是1→2→任务发送完成→3,虽然2. Finishing Out of Loop会提前打印,但Spinner的移除时机是正确的——只有等发送任务完成后才会执行。

额外提醒

要确保sendMessageQueueToDCSBIOS()方法是线程安全的,因为现在它是在biosQueue这个独立队列里执行的,避免出现多线程资源竞争的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 00:17:28