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

Swift 3环境下多计时器的实例化与跟踪问题咨询

Hey Danf, 作为刚接触Swift的电子工程师,遇到多Timer管理的问题太正常了——咱们结合你这个数据记录仪APP的场景,一步步来解决这个需求!

核心思路:用「设备唯一标识」绑定并跟踪Timer

每个数据记录仪(sensor)应该有一个唯一的标识(比如设备UUID、自定义ID),我们可以用这个标识作为Key,把Timer存入字典来实现精准跟踪。下面分两种方案给你参考:

方案1:直接在ViewController中管理Timer

如果你的逻辑比较简单,直接在传感器配置页面的ViewController里维护一个字典即可:

1. 定义Timer存储容器

在ViewController顶部声明一个字典,用来绑定设备ID和对应的Timer:

// 假设设备ID是String类型,你也可以根据实际用UUID等类型
var deviceTimers: [String: Timer] = [:]
// 记录当前选中的设备ID
var currentDeviceId: String?

2. 点击捕获按钮时创建并跟踪Timer

点击数据捕获按钮后,先清理该设备已有的Timer(避免重复触发),再创建新Timer并存入字典:

@IBAction func captureButtonTapped(_ sender: UIButton) {
    guard let deviceId = currentDeviceId else { return }
    
    // 先停止该设备已在运行的Timer(如果有)
    if let existingTimer = deviceTimers[deviceId] {
        existingTimer.invalidate()
        deviceTimers.removeValue(forKey: deviceId)
    }
    
    // 创建30秒后触发的Timer
    let timer = Timer.scheduledTimer(withTimeInterval: 30.0, repeats: false) { [weak self] timer in
        guard let self = self else { return }
        // 执行同步并获取传感器数据的逻辑
        self.syncAndFetchData(fromDevice: deviceId)
        // 任务完成后,从字典中移除该Timer
        self.deviceTimers.removeValue(forKey: deviceId)
    }
    
    // 将Timer存入字典跟踪
    deviceTimers[deviceId] = timer
}

3. 页面退出时清理Timer

用户在Timer触发前离开配置页面时,要及时停止并移除对应Timer,避免内存泄漏或无效任务:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    guard let deviceId = currentDeviceId, let timer = deviceTimers[deviceId] else { return }
    timer.invalidate()
    deviceTimers.removeValue(forKey: deviceId)
}

方案2:用单例类统一管理所有Timer(更优雅的架构)

如果你的APP需要同时处理多个设备的Timer,建议把Timer管理逻辑抽成单例类,和ViewController解耦:

1. 创建Timer管理单例

class DeviceTimerManager {
    // 单例实例,全局唯一
    static let shared = DeviceTimerManager()
    // 私有字典存储设备ID和Timer的映射
    private var timers: [String: Timer] = [:]
    
    // 禁止外部初始化,保证单例唯一性
    private init() {}
    
    /// 为指定设备启动30秒Timer
    func startTimer(forDeviceId deviceId: String, completion: @escaping () -> Void) {
        // 先停止该设备已有的Timer
        stopTimer(forDeviceId: deviceId)
        
        let timer = Timer.scheduledTimer(withTimeInterval: 30.0, repeats: false) { [weak self] _ in
            completion()
            // 任务完成后移除Timer
            self?.timers.removeValue(forKey: deviceId)
        }
        timers[deviceId] = timer
    }
    
    /// 停止指定设备的Timer
    func stopTimer(forDeviceId deviceId: String) {
        if let timer = timers[deviceId] {
            timer.invalidate()
            timers.removeValue(forKey: deviceId)
        }
    }
    
    /// 停止所有Timer(比如APP进入后台时调用)
    func stopAllTimers() {
        timers.values.forEach { $0.invalidate() }
        timers.removeAll()
    }
}

2. 在ViewController中调用

// 点击捕获按钮时
@IBAction func captureButtonTapped(_ sender: UIButton) {
    guard let deviceId = currentDeviceId else { return }
    DeviceTimerManager.shared.startTimer(forDeviceId: deviceId) { [weak self] in
        self?.syncAndFetchData(fromDevice: deviceId)
    }
}

// 页面退出时
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    guard let deviceId = currentDeviceId else { return }
    DeviceTimerManager.shared.stopTimer(forDeviceId: deviceId)
}
关键注意事项
  • 避免循环引用:Timer的闭包里一定要用[weak self],否则会导致ViewController无法被释放,造成内存泄漏。
  • 唯一标识必须可靠:设备ID要保证全局唯一,不能重复,否则会导致Timer被错误覆盖。
  • 及时清理Timer:无论任务完成、页面退出还是APP进入后台,都要调用invalidate()停止Timer并从容器中移除,避免无效运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:49:32