Search code examples
swiftswiftuiaccelerometergyroscopesensors

What's wrong with this code and how can I show the data on screen


I wrote this code to show the sensors data and to read and show them in swiftui, it doesn't work unfortunately. can someone help me ?? there's some bugs in swiftui and I have some errors but the most important is first to get the sensor data. is it the correct code to read data for accelerometer and gyroscope ?

'''

  HStack{
                Button("Start") {
                  // start()
                             
                } .padding()
                Button("Stop") {
                  // start()
                             
                } .padding()
              
            }                      
        }       
    }
   func start(){
       
        self.motionManager.gyroUpdateInterval = 0.5
           motionManager.startGyroUpdates(to: OperationQueue.current!) { (data, error) in
            print(data as Any)
                 
             if let data = self.motionManager.gyroData {
                let xG = data.rotationRate.x
                let yG = data.rotationRate.y
                let zG = data.rotationRate.z
               
                self.appendReadingGyroscope(x: xG, y: yG, z: zG)
                // Use the gyroscope data in your app.
             }
     
    }
          
        
    self.motionManager.accelerometerUpdateInterval = 0.5
        motionManager.startAccelerometerUpdates(to: OperationQueue.current!) { (data, error) in
               print(data as Any)
                  
          
            if let data = self.motionManager.accelerometerData {
                  let xA = data.acceleration.x
                  let yA = data.acceleration.y
                  let zA = data.acceleration.z
                  
                self.appendReadingAccelerometer(x: xA, y: yA, z: zA)
              
                  // Use the accelerometer data in your app.
               }
           }
       }
    func stop() {
         
             self.motionManager.stopGyroUpdates()
             self.motionManager.stopAccelerometerUpdates()
          }

'''

Solution

  • You've got a couple of problems with your code.

    First, try to separate your MotionManager from your ContentView and use Combine to read the properties when they update.

    I built a MotionManager class. MotionManagerclass is an ObservableObject (Combine) because we need to implement x, y and z as @Published properties in order to read them in our ContentView when they update.

    Here's the class MotionManager :

    class MotionManager: ObservableObject {
        // MotionManager use the ObservableObject Combine property.
        private var motionManager: CMMotionManager
    
        @Published
        var x: Double = 0.0
        @Published
        var y: Double = 0.0
        @Published
        var z: Double = 0.0
        // x, y and z use are Published so ContentView can read the values when they update.
    
        // init
        init() {
            self.motionManager = CMMotionManager()
            self.motionManager.magnetometerUpdateInterval = 0.5
            self.motionManager.startMagnetometerUpdates(to: .main) { (magnetometerData, error) in
                guard error == nil else {
                    print(error!)
                    return
                }
    
                if let magnetData = magnetometerData {
                    self.x = magnetData.magneticField.x
                    self.y = magnetData.magneticField.y
                    self.z = magnetData.magneticField.z
                }
    
            }
    
        }
    }
    

    And now here's your ContentView. It's way more cleaner. Here you can implement your buttons if you want to.

    In your ContentView, you now need to instanciate the MotionManager class in order to access x, y and z @Published properties.

    struct ContentView: View {
        
        @ObservedObject var motion: MotionManager
        // You need to instanciate your MotionManager class as an ObservedObject to use x, y and z when the update
        
        var body: some View {
            
            VStack {
                        Text("Magnetometer Data")
                        Text("X: \(motion.x)")
                        Text("Y: \(motion.y)")
                        Text("Z: \(motion.z)")
                    }
        }
    }
    

    Please note that you'll need to pass your MotionManager() into the preview code and in the WindowGroup in order to compile : ContentView(motion: MotionManager())

    I hope my code will help you understand what's going wrong in yours. If not, feel free to ask.

    ------- EDIT

    I implemented start() and stop() functions.

    //
    //  ContentView.swift
    //  todeletenow
    //
    //  Created by Théo Voglimacci on 29/09/2020.
    //
    
    import SwiftUI
    import Combine
    import CoreMotion
    
    struct ContentView: View {
        
        @ObservedObject var motion: MotionManager
        // You need to instanciate your MotionManager class as an ObservedObject to use x, y and z when the update
        
        var body: some View {
            
            HStack {
                
                Button("Start") {
                    motion.start()
                    
                } .padding()
                
                Button("Stop") {
                    motion.stop()
                    
                } .padding()
                
            }
            
            VStack {
                Text("Magnetometer Data")
                Text("X: \(motion.x)")
                Text("Y: \(motion.y)")
                Text("Z: \(motion.z)")
            }
        }
    }
    
    class MotionManager: ObservableObject {
        // MotionManager use the ObservableObject Combine property.
        private var motionManager: CMMotionManager
        
        @Published
        var x: Double = 0.0
        @Published
        var y: Double = 0.0
        @Published
        var z: Double = 0.0
        // x, y and z use are Published so ContentView can read the values when they update.
        
        func start() {
            motionManager.startMagnetometerUpdates(to: .main) { (magnetometerData, error) in
                guard error == nil else {
                    print(error!)
                    return
                }
                
                if let magnetData = magnetometerData {
                    self.x = magnetData.magneticField.x
                    self.y = magnetData.magneticField.y
                    self.z = magnetData.magneticField.z
                }
                
            }
        }
        
        func stop() {
            motionManager.stopMagnetometerUpdates()
        }
        
        // init
        init() {
            self.motionManager = CMMotionManager()
            self.motionManager.magnetometerUpdateInterval = 0.5
            self.motionManager.startMagnetometerUpdates(to: .main) { (magnetometerData, error) in
                guard error == nil else {
                    print(error!)
                    return
                }
                
                if let magnetData = magnetometerData {
                    self.x = magnetData.magneticField.x
                    self.y = magnetData.magneticField.y
                    self.z = magnetData.magneticField.z
                }
                
            }
            
        }
    }
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView(motion: MotionManager())
        }
    }