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
相关产品推荐
相关产品推荐

