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

iOS开发:两个ViewController间传递双精度数值并维持计数

解决iOS ViewController间持续计数的数据同步问题

嘿,我明白你要做的事了——在ViewController1和ViewController2之间切换时,让计数器持续运转,而且两个页面都能获取到实时的计数数值对吧?直接在prepare(for:sender:)里传值肯定行不通,因为Double是值类型,传过去的只是当前counter的副本,后续VC1里的counter更新不会同步到VC2;而且如果VC1被销毁,计时器也会跟着停止。下面给你几个可行的方案:

方案一:用单例管理计数器与计时器(最直观的方案)

我们可以把计数器和计时器的逻辑抽离到一个单例类里,这样不管是VC1还是VC2,访问的都是同一个数据源,计时器的生命周期也不依赖单个ViewController。

1. 创建单例管理类

class CounterManager {
    // 单例实例,全局唯一
    static let shared = CounterManager()
    
    // 对外只读的计数器,只能内部修改
    private(set) var counter: Double = 0.00
    private var timer: Timer?
    
    // 私有初始化方法,防止外部创建实例
    private init() {}
    
    // 启动计时器
    func startTimer() {
        // 避免重复启动
        guard timer == nil else { return }
        timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateCounter), userInfo: nil, repeats: true)
    }
    
    // 停止计时器
    func stopTimer() {
        timer?.invalidate()
        timer = nil
    }
    
    // 内部更新计数器的方法
    @objc private func updateCounter() {
        counter += 0.1
        // 发送通知,通知所有监听页面更新UI
        NotificationCenter.default.post(name: NSNotification.Name("CounterUpdated"), object: counter)
    }
}

2. 修改ViewController1的代码

class ViewController1: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // 进入页面就启动计时器
        CounterManager.shared.startTimer()
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let vc2 = segue.destination as? ViewController2 {
            // 给VC2传递当前的初始计数器值
            vc2.currentCounter = CounterManager.shared.counter
        }
    }
    
    deinit {
        // 可选:如果退出VC1后不需要继续计数,可以在这里停止计时器
        // CounterManager.shared.stopTimer()
    }
}

3. 修改ViewController2的代码

class ViewController2: UIViewController {
    // 接收初始的计数器值
    var currentCounter: Double = 0.00
    // 保存通知监听的引用,用于销毁时移除
    private var notificationObserver: NSObjectProtocol?
    
    // 假设你有一个显示计数器的UILabel
    @IBOutlet weak var counterLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 初始化显示当前计数器值
        updateCounterLabel()
        
        // 监听计数器更新的通知,实时同步数值
        notificationObserver = NotificationCenter.default.addObserver(forName: NSNotification.Name("CounterUpdated"), object: nil, queue: .main) { [weak self] notification in
            guard let newCounter = notification.object as? Double else { return }
            self?.currentCounter = newCounter
            self?.updateCounterLabel()
        }
    }
    
    // 更新UI的方法
    private func updateCounterLabel() {
        counterLabel.text = String(format: "%.2f", currentCounter)
    }
    
    deinit {
        // 销毁页面时移除通知监听,避免内存泄漏
        if let observer = notificationObserver {
            NotificationCenter.default.removeObserver(observer)
        }
    }
}

方案二:用Combine框架实现响应式同步(Swift 5+推荐)

如果你的项目用的是Swift 5及以上版本,Combine框架能更优雅地实现数据同步,不需要手动管理通知:

1. 修改单例类(引入Combine)

import Combine

class CounterManager {
    static let shared = CounterManager()
    
    // 使用@Published包装计数器,自动发送更新通知
    @Published var counter: Double = 0.00
    private var timer: Timer?
    
    private init() {}
    
    func startTimer() {
        guard timer == nil else { return }
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
            self?.counter += 0.1
        }
    }
    
    func stopTimer() {
        timer?.invalidate()
        timer = nil
    }
}

2. 修改ViewController2的代码

import Combine

class ViewController2: UIViewController {
    @IBOutlet weak var counterLabel: UILabel!
    // 保存订阅引用,防止被提前释放
    private var cancellables = Set<AnyCancellable>()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 订阅计数器的更新,实时同步到UI
        CounterManager.shared.$counter
            .receive(on: DispatchQueue.main) // 确保在主线程更新UI
            .sink { [weak self] newCounter in
                self?.counterLabel.text = String(format: "%.2f", newCounter)
            }
            .store(in: &cancellables)
    }
}

注意事项

  • 记得在合适的时机停止计时器(比如应用进入后台、用户退出计数页面时),避免不必要的资源消耗和内存泄漏。
  • 使用闭包或通知时,一定要用[weak self]避免循环引用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:34:50