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

Swift中如何从Timer触发的函数返回值并跨文件获取howHungry更新值?

Timer更新值无法回传的问题解决

问题描述

创建了一个每5秒触发的Timer,timerFire函数接收来自file1.swift的Double类型值howHungry,每次触发将其减1,但更新后的值无法传回file1,导致控制台重复输出初始值(例如"Hunger value is 14.0")。

原代码

file1.swift

let hungerTimer = myTimer()

hungerTimer.startTimer(timerInitialValue: howHungry)

file2.swift

func startTimer(timerInitialValue:Double){
    
    if timer == nil{ //如果不存在饥饿计时器则创建新的
        timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(timerFire(sender:)), userInfo: timerInitialValue/*饥饿值*/, repeats: true)
        print("New Timer Started")

    }else{ //如果计时器已存在,先停止再启动新的

        timer!.invalidate()
        timer = nil
        print("Old Timer Stopped")
        timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(timerFire(sender:)), userInfo: timerInitialValue, repeats: true)
        print ("Now New Timer Started")
        print(timer)
    }
}

@objc func timerFire(sender: Timer) -> Double{
    //从Timer获取饥饿值
    var hungryDouble = sender.userInfo as! Double
    //减1
    hungryDouble -= 1.0
    print("Hunger value is \(hungryDouble)")
    return(hungryDouble)
}

问题原因

  1. 值类型传递特性:Double是值类型,传给Timer的userInfo是初始值的副本,timerFire里修改的只是这个副本,不会影响file1中的原变量。
  2. Timer selector无法接收返回值:timerFire的返回值完全没用,因为Timer通过selector调用方法时,不会处理返回值,所以更新后的值根本传不回file1。

解决方案

方案一:闭包回调(推荐)

通过闭包将更新后的值回调给file1,这是Swift中跨文件传递更新值的常用方式。

修改后的file2.swift

class myTimer {
    var timer: Timer?
    // 定义回调闭包,用于传递更新后的饥饿值
    var onHungerUpdated: ((Double) -> Void)?

    func startTimer(timerInitialValue: Double) {
        // 先停止已有计时器
        timer?.invalidate()
        timer = nil

        var currentHunger = timerInitialValue
        // 使用block式Timer,避免selector的局限
        timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { [weak self] _ in
            currentHunger -= 1.0
            print("饥饿值为 \(currentHunger)")
            // 调用闭包传递更新后的值
            self?.onHungerUpdated?(currentHunger)
        }
        print("新计时器已启动")
    }
}

修改后的file1.swift

// 假设howHungry是file1中的变量
var howHungry: Double = 14.0
let hungerTimer = myTimer()

// 设置回调,接收更新后的饥饿值
hungerTimer.onHungerUpdated = { updatedValue in
    howHungry = updatedValue
    // 这里可以添加UI更新等逻辑
}

hungerTimer.startTimer(timerInitialValue: howHungry)

方案二:使用引用类型包装值

把Double包装成类(引用类型),这样传递的是实例引用,修改时会直接改变原对象的值。

定义包装类

class HungerWrapper {
    var value: Double
    init(value: Double) {
        self.value = value
    }
}

修改后的file2.swift

class myTimer {
    var timer: Timer?

    func startTimer(hungerWrapper: HungerWrapper){
        timer?.invalidate()
        timer = nil

        timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(timerFire(sender:)), userInfo: hungerWrapper, repeats: true)
        print("新计时器已启动")
    }

    @objc func timerFire(sender: Timer){
        guard let hungerWrapper = sender.userInfo as? HungerWrapper else { return }
        hungerWrapper.value -= 1.0
        print("饥饿值为 \(hungerWrapper.value)")
    }
}

修改后的file1.swift

let hungerWrapper = HungerWrapper(value: 14.0)
let hungerTimer = myTimer()

hungerTimer.startTimer(hungerWrapper: hungerWrapper)

// 后续可以通过hungerWrapper.value获取更新后的值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 01:55:21