Core Motion provides access to device motion and orientation data. Learn to work with accelerometer, gyroscope, and other sensors.
Motion Manager Setup
Initialize Motion Manager
swiftimport CoreMotion import SwiftUI class MotionManager: ObservableObject { private let motionManager = CMMotionManager() @Published var accelerometerData: CMAccelerometerData? @Published var gyroData: CMGyroData? @Published var deviceMotion: CMDeviceMotion? init() { setupMotionUpdates() } func setupMotionUpdates() { // Accelerometer if motionManager.isAccelerometerAvailable { motionManager.accelerometerUpdateInterval = 0.1 motionManager.startAccelerometerUpdates(to: .main) { [weak self] data, error in self?.accelerometerData = data } } // Gyroscope if motionManager.isGyroAvailable { motionManager.gyroUpdateInterval = 0.1 motionManager.startGyroUpdates(to: .main) { [weak self] data, error in self?.gyroData = data } } // Device Motion if motionManager.isDeviceMotionAvailable { motionManager.deviceMotionUpdateInterval = 0.1 motionManager.startDeviceMotionUpdates(to: .main) { [weak self] data, error in self?.deviceMotion = data } } } func stopUpdates() { motionManager.stopAccelerometerUpdates() motionManager.stopGyroUpdates() motionManager.stopDeviceMotionUpdates() } }
Accelerometer
Accelerometer Data
swiftstruct AccelerometerView: View { @StateObject private var motionManager = MotionManager() var body: some View { VStack(spacing: 20) { Text("Accelerometer") .font(.title) if let data = motionManager.accelerometerData { HStack { VStack { Text("X") .font(.headline) Text(String(format: "%.2f", data.acceleration.x)) .font(.title) } VStack { Text("Y") .font(.headline) Text(String(format: "%.2f", data.acceleration.y)) .font(.title) } VStack { Text("Z") .font(.headline) Text(String(format: "%.2f", data.acceleration.z)) .font(.title) } } } } .onAppear { motionManager.setupMotionUpdates() } .onDisappear { motionManager.stopUpdates() } } }
Shake Detection
swiftclass ShakeDetector: ObservableObject { @Published var isShaken = false private let motionManager = CMMotionManager() func startDetection() { motionManager.accelerometerUpdateInterval = 0.2 motionManager.startAccelerometerUpdates(to: .main) { [weak self] data, error in guard let data = data else { return } let acceleration = sqrt( pow(data.acceleration.x, 2) + pow(data.acceleration.y, 2) + pow(data.acceleration.z, 2) ) if acceleration > 2.5 { self?.isShaken = true DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self?.isShaken = false } } } } func stopDetection() { motionManager.stopAccelerometerUpdates() } }
Gyroscope
Rotation Rate
swiftclass GyroscopeManager: ObservableObject { @Published var rotationRate: CMRotationRate? private let motionManager = CMMotionManager() func startGyroscope() { guard motionManager.isGyroAvailable else { print("Gyroscope not available") return } motionManager.gyroUpdateInterval = 0.1 motionManager.startGyroUpdates(to: .main) { [weak self] data, error in self?.rotationRate = data?.rotationRate } } func stopGyroscope() { motionManager.stopGyroUpdates() } var totalRotation: Double { guard let rate = rotationRate else { return 0 } return sqrt(pow(rate.x, 2) + pow(rate.y, 2) + pow(rate.z, 2)) } }
Device Orientation
Orientation Tracking
swiftclass OrientationManager: ObservableObject { @Published var orientation: UIDeviceOrientation = .portrait init() { startTracking() } func startTracking() { UIDevice.current.beginGeneratingDeviceOrientationNotifications() NotificationCenter.default.addObserver( forName: UIDevice.orientationDidChangeNotification, object: UIDevice.current, queue: .main ) { [weak self] _ in self?.orientation = UIDevice.current.orientation } } func stopTracking() { UIDevice.current.endGeneratingDeviceOrientationNotifications() } }
Pedometer
Step Counting
swiftimport CoreMotion class PedometerManager: ObservableObject { @Published var stepCount: Int = 0 @Published var distance: Double = 0 private let pedometer = CMPedometer() func startStepCounting() { guard CMPedometer.isStepCountingAvailable() else { print("Step counting not available") return } pedometer.startUpdates(from: Date()) { [weak self] data in DispatchQueue.main.async { self?.stepCount = data.numberOfSteps.intValue self?.distance = data.distance?.doubleValue ?? 0 } } } func stopStepCounting() { pedometer.stopUpdates() } func queryStepsSince(_ date: Date) { pedometer.queryStepCountStarting(from: date, to: Date()) { data, error in if let data = data { DispatchQueue.main.async { self.stepCount = data.numberOfSteps.intValue } } } } }
Magnetometer
Compass Heading
swiftclass MagnetometerManager: ObservableObject { @Published var heading: Double = 0 private let motionManager = CMMotionManager() func startMagnetometer() { if motionManager.isMagnetometerAvailable { motionManager.magnetometerUpdateInterval = 0.1 motionManager.startMagnetometerUpdates(to: .main) { [weak self] data, error in guard let data = data else { return } let magneticField = data.magneticField let magnitude = sqrt( pow(magneticField.x, 2) + pow(magneticField.y, 2) + pow(magneticField.z, 2) ) self?.heading = Double(atan2(magneticField.y, magneticField.x)) } } } func stopMagnetometer() { motionManager.stopMagnetometerUpdates() } }
Altimeter
Altitude Tracking
swiftimport CoreMotion class AltimeterManager: ObservableObject { @Published var altitude: Double = 0 @Published var pressure: Double = 0 private let altimeter = CMAltimeter() func startAltimeter() { guard CMAltimeter.isRelativeAltitudeAvailable() else { print("Altimeter not available") return } altimeter.startRelativeAltitudeUpdates(to: .main) { [weak self] data, error in guard let data = data else { return } DispatchQueue.main.async { self?.altitude = data.relativeAltitude.doubleValue self?.pressure = data.pressure.doubleValue } } } func stopAltimeter() { altimeter.stopRelativeAltitudeUpdates() } }
Motion Activity
Activity Recognition
swiftimport CoreMotion class ActivityManager: ObservableObject { @Published var currentActivity: String = "Unknown" private let activityManager = CMMotionActivityManager() func startActivityUpdates() { activityManager.startActivityUpdates(to: .main) { [weak self] activity in guard let activity = activity else { return } var activityString = "Unknown" if activity.walking { activityString = "Walking" } else if activity.running { activityString = "Running" } else if activity.automotive { activityString = "Driving" } else if activity.stationary { activityString = "Stationary" } else if activity.cycling { activityString = "Cycling" } DispatchQueue.main.async { self?.currentActivity = activityString } } } func stopActivityUpdates() { activityManager.stopActivityUpdates() } func queryHistoricalActivity(from start: Date, to end: Date) { let query = CMMotionActivityQuery() query.from = start query.to = end activityManager.queryHistoricalActivity(with: query) { activities, error in if let activities = activities { for activity in activities { print("Activity: \(activity)") } } } } }
Best Practices
- 1Battery: Minimize sensor usage
- 2Permissions: Request appropriate permissions
- 3Updates: Use appropriate update intervals
- 4Filtering: Filter sensor noise
- 5Calibration: Calibrate when needed
- 6Performance: Optimize for performance
- 7Testing: Test on real devices
- 8UX: Provide clear visual feedback
Core Motion enables motion-aware and sensor-rich applications!