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
CMMotionManagerinitialization: You're referencingmotionManagerbut 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 benil, 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 ofstop(). - No reactive state for UI updates: You have
appendReadingGyroscope/appendReadingAccelerometerbut 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
- Proper Motion Manager Setup: The view model handles
CMMotionManagerinitialization and lifecycle, using@StateObjectto keep it alive for the view's lifetime. - Safe Queue Handling: We use
.mainqueue 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. - Reactive UI Updates:
@Publishedvariables automatically trigger view refreshes when sensor data changes, so your UI will update in real-time. - Fixed Stop Button: The Stop button now correctly calls
viewModel.stop(). - 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 likeNSMotionUsageDescriptionwith 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
相关产品推荐
相关产品推荐

