Skip to content
All essays
iOSMarch 27, 202512 min

Swift Core Motion: Sensor Data and Motion

Access device sensors with Core Motion. Accelerometer, gyroscope, and device motion.

Ü
Ümit Uz
Mobile & Full Stack Developer

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

swift
import 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

swift
struct 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

swift
class 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

swift
class 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

swift
class 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

swift
import 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

swift
class 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

swift
import 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

swift
import 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

  1. 1Battery: Minimize sensor usage
  2. 2Permissions: Request appropriate permissions
  3. 3Updates: Use appropriate update intervals
  4. 4Filtering: Filter sensor noise
  5. 5Calibration: Calibrate when needed
  6. 6Performance: Optimize for performance
  7. 7Testing: Test on real devices
  8. 8UX: Provide clear visual feedback

Core Motion enables motion-aware and sensor-rich applications!

Next essay
Swift PassKit: Apple Wallet Integration