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

Swift 6中如何在Actor内启动定时器实现Ping功能?

在Swift 6后台线程实现定时Ping功能的解决方案

问题原因

你的代码中ping()未被调用的核心原因是:Timer依赖RunLoop运行,但TimerActor执行线程的RunLoop并未启动循环。当调用await actor.start()时,start方法在TimerActor的串行执行线程上运行,虽然你创建了Timer并添加到当前RunLoop,但后台线程的RunLoop默认不会自动启动,导致Timer永远无法触发。

推荐解决方案:使用Swift Concurrency原生实现(无需Timer/RunLoop)

这种方式更贴合Swift 6的并发设计,无需手动管理RunLoop,代码简洁且安全:

actor TimerActor {
    private var isRunning = false
    
    func start() {
        guard !isRunning else { return }
        isRunning = true
        
        // 启动循环任务,每隔2秒执行一次ping
        Task { [weak self] in
            guard let self = self else { return }
            while self.isRunning {
                self.ping()
                // 等待2秒,允许取消
                try? await Task.sleep(for: .seconds(2))
            }
        }
    }
    
    func stop() {
        // 停止循环
        isRunning = false
    }
    
    func ping() {
        print("send ping at \(Date())")
    }
}

使用示例

class ViewController: UIViewController {
    let actor = TimerActor()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        Task {
            await actor.start()
        }
    }
    
    // 页面销毁时停止定时任务
    deinit {
        Task {
            await actor.stop()
        }
    }
}

可选方案:修复Timer+RunLoop的实现(不推荐)

如果一定要使用Timer,需要确保RunLoop持续运行,同时避免阻塞Actor的串行执行:

actor TimerActor {
    private var timer: Timer?
    private var runLoopTask: Task<Void, Never>?
    
    func start() {
        guard runLoopTask == nil else { return }
        
        runLoopTask = Task {
            let runLoop = RunLoop.current
            timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { [weak self] timer in
                guard let self = self else {
                    timer.invalidate()
                    return
                }
                Task { await self.ping() }
            }
            runLoop.add(timer!, forMode: .common)
            
            // 启动RunLoop,当Task取消或无事件时退出
            while !Task.isCancelled && runLoop.run(mode: .common, before: .distantFuture) {}
        }
    }
    
    func stop() {
        timer?.invalidate()
        timer = nil
        runLoopTask?.cancel()
        runLoopTask = nil
    }
    
    func ping() {
        print("send ping at \(Date())")
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 22:23:16