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

CoreMotion结合定时器问题:未触发STOPMAP/STARTMAP输出排查

问题分析与修复方案

核心问题点

  • Timer变量作用域错误:timer是viewDidLoad内的局部变量,calculate()方法无法访问该变量,编译时就会报错,导致代码无法正常执行。
  • 闭包内方法调用缺失self:在CoreMotion的回调闭包中调用calculate()时,没有显式使用self.,Swift闭包语境下会导致方法无法被正确调用。
  • 逻辑触发时机错误:当前代码在检测到stationary状态时直接调用calculate(),此时second还未开始有效累计,不符合“5秒后判断”的需求,应该是进入stationary状态后启动定时器,累计到指定时间再执行判断。

修复后的代码

import UIKit
import CoreMotion

private let motionActivityManager = CMMotionActivityManager()

class ViewController: UIViewController {

    @IBOutlet weak var lblActivity: UILabel!
    
    var second = 0
    var timer: Timer? // 将timer改为实例变量,让整个类可访问
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        motionActivityManager.startActivityUpdates(to: OperationQueue.main) { (activity: CMMotionActivity?) in
            guard let activity = activity else { return }
            DispatchQueue.main.async {
                if activity.stationary {
                    self.lblActivity.text = "Stationary"
                    print("Stationary")
                    
                    // 进入静止状态时重置计数并启动定时器
                    self.second = 0
                    self.timer?.invalidate() // 先销毁旧定时器,避免重复创建
                    self.timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.calculateSeconds), userInfo: nil, repeats: true)
                    
                } else {
                    // 离开静止状态时销毁定时器并重置计数
                    self.timer?.invalidate()
                    self.second = 0
                    
                    if activity.walking {
                        self.lblActivity.text = "Walking"
                        print("Walking")
                    } else if activity.running {
                        self.lblActivity.text = "Running"
                        print("Running")
                    } else if activity.automotive {
                        self.lblActivity.text = "Automotive"
                        print("Automotive")
                    }
                }
            }
        }
    }
    
    @objc func calculateSeconds() {
        second += 1
        // 每秒检查累计时间,执行对应逻辑
        if second >= 5 {
            self.stopMap()
            self.timer?.invalidate()
            self.timer = nil
            self.second = 0
        } else {
            self.startMap()
        }
    }
    
    func stopMap() {
        print("STOPMAP")
    }
    
    func startMap() {
        print("STARTMAP")
    }
}

关键修复说明

  • 将timer改为ViewController的实例变量,确保类内所有方法能正常操作定时器。
  • 调整逻辑:进入stationary状态时启动定时器并重置计数,离开静止状态时立即销毁定时器,避免无效计数。
  • 将判断逻辑移到calculateSeconds()中,每秒钟检查累计时间,达到5秒时调用stopMap()并销毁定时器,未达到时调用startMap()。
  • 闭包内所有调用类方法/属性的地方添加self.,确保Swift能正确解析上下文。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 06:33:31