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

SwiftUI传感器数据读取异常求助:代码正确性排查与数据显示

Fixing SwiftUI Gyroscope & Accelerometer Data Reading & Display Issues

Let's walk through the problems in your code and get it working properly—there are a few key issues preventing sensor data from being read and displayed correctly.

Key Problems in Your Current Code

  • Missing CMMotionManager initialization: You're referencing motionManager but never creating an instance of it. Plus, in SwiftUI, we need to manage this reference type properly with a view model to avoid lifecycle issues.
  • Incorrect queue usage: Using OperationQueue.current! is risky (it can be nil, leading to crashes) and sensor updates often come on a background queue—you need to explicitly update UI state on the main queue.
  • Stop button action bug: Your Stop button calls start() instead of stop().
  • No reactive state for UI updates: You have appendReadingGyroscope/appendReadingAccelerometer but no reactive variables (like @Published) to trigger UI refreshes when data changes.

Corrected Implementation

First, create a view model to handle sensor logic (follows MVVM and keeps your view clean):

import SwiftUI
import CoreMotion

class SensorViewModel: ObservableObject {
    // Motion manager instance
    private let motionManager = CMMotionManager()
    
    // Reactive variables to store sensor data (triggers UI updates)
    @Published var gyroData: (x: Double, y: Double, z: Double) = (0, 0, 0)
    @Published var accelerometerData: (x: Double, y: Double, z: Double) = (0, 0, 0)
    
    func start() {
        guard motionManager.isGyroAvailable, motionManager.isAccelerometerAvailable else {
            print("Gyro or Accelerometer not available on this device")
            return
        }
        
        // Configure gyro updates
        motionManager.gyroUpdateInterval = 0.5
        motionManager.startGyroUpdates(to: .main) { [weak self] data, error in
            guard let self = self, let gyroData = data else {
                if let error = error {
                    print("Gyro update error: \(error.localizedDescription)")
                }
                return
            }
            self.gyroData = (gyroData.rotationRate.x, gyroData.rotationRate.y, gyroData.rotationRate.z)
        }
        
        // Configure accelerometer updates
        motionManager.accelerometerUpdateInterval = 0.5
        motionManager.startAccelerometerUpdates(to: .main) { [weak self] data, error in
            guard let self = self, let accelData = data else {
                if let error = error {
                    print("Accelerometer update error: \(error.localizedDescription)")
                }
                return
            }
            self.accelerometerData = (accelData.acceleration.x, accelData.acceleration.y, accelData.acceleration.z)
        }
    }
    
    func stop() {
        motionManager.stopGyroUpdates()
        motionManager.stopAccelerometerUpdates()
        // Reset data when stopping
        gyroData = (0, 0, 0)
        accelerometerData = (0, 0, 0)
    }
}

Then, update your SwiftUI view to use this view model and display the data:

struct SensorView: View {
    // Manage the view model lifecycle
    @StateObject private var viewModel = SensorViewModel()
    
    var body: some View {
        VStack(spacing: 20) {
            HStack{
                Button("Start") {
                    viewModel.start()
                }
                .padding()
                .background(Color.green)
                .foregroundColor(.white)
                .cornerRadius(8)
                
                Button("Stop") {
                    viewModel.stop()
                }
                .padding()
                .background(Color.red)
                .foregroundColor(.white)
                .cornerRadius(8)
            }
            
            // Display Gyroscope Data
            VStack(spacing: 10) {
                Text("Gyroscope Data")
                    .font(.headline)
                Text("X: \(viewModel.gyroData.x, specifier: "%.2f")")
                Text("Y: \(viewModel.gyroData.y, specifier: "%.2f")")
                Text("Z: \(viewModel.gyroData.z, specifier: "%.2f")")
            }
            
            // Display Accelerometer Data
            VStack(spacing: 10) {
                Text("Accelerometer Data")
                    .font(.headline)
                Text("X: \(viewModel.accelerometerData.x, specifier: "%.2f")")
                Text("Y: \(viewModel.accelerometerData.y, specifier: "%.2f")")
                Text("Z: \(viewModel.accelerometerData.z, specifier: "%.2f")")
            }
        }
        .padding()
    }
}

// Preview
struct SensorView_Previews: PreviewProvider {
    static var previews: some View {
        SensorView()
    }
}

What We Fixed

  1. Proper Motion Manager Setup: The view model handles CMMotionManager initialization and lifecycle, using @StateObject to keep it alive for the view's lifetime.
  2. Safe Queue Handling: We use .main queue for updates so UI state changes happen on the main thread (avoids crashes and UI glitches). We also use [weak self] to prevent retain cycles.
  3. Reactive UI Updates: @Published variables automatically trigger view refreshes when sensor data changes, so your UI will update in real-time.
  4. Fixed Stop Button: The Stop button now correctly calls viewModel.stop().
  5. Error Handling: Added checks for sensor availability and error logging to help debug issues on devices without gyro/accelerometer support.

Important Notes

  • Don't forget to add the Privacy - Motion Usage Description to your Info.plist (required by iOS to access motion sensors). Add a key like NSMotionUsageDescription with a message explaining why your app needs this data.
  • Testing on a physical device is best—simulators don't provide real gyro/accelerometer data.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 10:57:52