Fitness App iOS Swift Tutorial iOS8

iOS Swift Development : Step Counter app using Pedometer data

We will be building a simple step counter app which uses a pedometer data to retrieve step counts and other information about the distance traveled and the number of floors ascended or descended. The pedometer object manages a cache of historic data that you can query or you can ask for live updates as the data is processed.

The CMMotionActivity class contains the data for a single motion update event. On devices that support motion, you can use a CMMotionActivityManager object to request updates when the current type of motion changes. When a change occurs, the update information is packaged into a CMMotionActivity object and sent to your app.

CMMotionActivity contains state related to many of the activites like stationary, walking, running, automative, cycling and unknown. Also along with that it provides confidence about how accurate the motion data is.

CMPedoMeter and CMMotionActivityManager will work on actual devices.

In the mainstory board let go ahead and start adding the UILabel’s and UIImageview.

  • Add Labels for the Today,Steps,Activity state.
  • Add imageview for the shoe and the state (Either running, walking, stationary,automotive)
  • Setup the IBOutlet for all the above.
  • More on autolayouts AutoLayout Part 1 and Autolayout part 2

images

images

There are multiple ways we can query the data from the CMPedometer and the CMActivityManager.

  • Realtime push as the events happen
  • Query cached data with start and end date.

In this app I am currently using both of the above methods. When the app starts up I fetch the data from midnight till now to get the steps for today and update the View.
self.pedoMeter.queryPedometerDataFromDate(midnightOfToday, toDate: NSDate())

Along with we utilize the realtime push from the framework to show the latest steps and the current activity.

self.pedoMeter.startPedometerUpdatesFromDate(midnightOfToday)

//
//  ViewController.swift
//  Steps
//
//  Created by Shrikar Archak on 4/11/15.
//  Copyright (c) 2015 Shrikar Archak. All rights reserved.
//

import UIKit
import CoreMotion
class ViewController: UIViewController {

    @IBOutlet weak var activityState: UILabel!
    @IBOutlet weak var steps: UILabel!
    
    var days:[String] = []
    var stepsTaken:[Int] = []
    
    @IBOutlet weak var stateImageView: UIImageView!
    let activityManager = CMMotionActivityManager()
    let pedoMeter = CMPedometer()
    
    override func viewDidLoad() {

        super.viewDidLoad()

        let cal = NSCalendar.currentCalendar()
        var comps = cal.components(NSCalendarUnit.YearCalendarUnit | .MonthCalendarUnit | .DayCalendarUnit | .HourCalendarUnit | .MinuteCalendarUnit | .SecondCalendarUnit, fromDate: NSDate())
        comps.hour = 0
        comps.minute = 0
        comps.second = 0
        let timeZone = NSTimeZone.systemTimeZone()
        cal.timeZone = timeZone
        
        let midnightOfToday = cal.dateFromComponents(comps)!
        

        if(CMMotionActivityManager.isActivityAvailable()){
            self.activityManager.startActivityUpdatesToQueue(NSOperationQueue.mainQueue(), withHandler: { (data: CMMotionActivity!) -> Void in
               dispatch_async(dispatch_get_main_queue(), { () -> Void in
                if(data.stationary == true){
                    self.activityState.text = "Stationary"
                    self.stateImageView.image = UIImage(named: "Sitting")
                } else if (data.walking == true){
                    self.activityState.text = "Walking"
                    self.stateImageView.image = UIImage(named: "Walking")
                } else if (data.running == true){
                    self.activityState.text = "Running"
                    self.stateImageView.image = UIImage(named: "Running")
                } else if (data.automotive == true){
                    self.activityState.text = "Automotive"
                }
               })
                
           })
        }
        if(CMPedometer.isStepCountingAvailable()){
            let fromDate = NSDate(timeIntervalSinceNow: -86400 * 7)
            self.pedoMeter.queryPedometerDataFromDate(fromDate, toDate: NSDate()) { (data : CMPedometerData!, error) -> Void in
                println(data)
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    if(error == nil){
                        self.steps.text = "\(data.numberOfSteps)"
                    }
                })

            }
  
            self.pedoMeter.startPedometerUpdatesFromDate(midnightOfToday) { (data: CMPedometerData!, error) -> Void in
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    if(error == nil){
                        self.steps.text = "\(data.numberOfSteps)"
                    }
                })
            }
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()

    }


}


About the author

Shrikar

Backend/Infrastructure Engineer by Day. iOS Developer for the rest of the time.

  • student

    for some reason it’s giving me an error for ”

    self.pedoMeter.queryPedometerDataFromDate(fromDate, toDate: NSDate()) { (data : CMPedometerData!, error) -> Void in ” – consecutive elements on a line must be separated by “;” . Even after adding the “;”, it’s giving errors. Do you know how to fix that?

    • Beginner

      I have the same issue. Anybody can help ?

      • https://shrikar.com shrikar

        What version of xcode are you using?

        • Norman Pettus

          I am using xcode 6.3.2. Mine is working or at least gives no errors. I haven’t tested it on my ipod yet.

      • Norman Pettus

        You must eliminate all ; and make sure all -> are in place of ->. This worked for me.

        • Norman Pettus

          The second -> is the dash ampersand g t semicolon. I missed the final ; when I edited the code and got the same error message.

          • Beginner

            Thanks :)

          • Anon

            When I replaced all the -> with ->, I got this error instead:
            Cannot invoke ‘queryPedometerDataFromDate’ with an argument list of type ‘(NSDate, toDate: NSDate, (CMPedometerData!, _) -> Void)’

    • https://shrikar.com shrikar

      Could you please provide the version of xcode and swift you are using?

      • Sara

        I have the same error and I’m using Xcode 7.3

  • Or

    can you explain
    that please?
    var comps = cal.components(NSCalendarUnit.YearCalendarUnit | .MonthCalendarUnit | .DayCalendarUnit | .HourCalendarUnit | .MinuteCalendarUnit | .SecondCalendarUnit, fromDate: NSDate())
    comps.hour = 0

    • https://shrikar.com shrikar

      That code will basically get the current day from Midnight 00:00:00 time . I want to find out all the steps which I have done today.
      let cal = NSCalendar.currentCalendar()
      var comps = cal.components(NSCalendarUnit.YearCalendarUnit | .MonthCalendarUnit | .DayCalendarUnit | .HourCalendarUnit | .MinuteCalendarUnit | .SecondCalendarUnit, fromDate: NSDate())
      comps.hour = 0
      comps.minute = 0
      comps.second = 0
      let timeZone = NSTimeZone.systemTimeZone()
      cal.timeZone = timeZone

      let midnightOfToday = cal.dateFromComponents(comps)!

      • Or

        Thank you for fast comment, I was meant to the line between calendar unit

        • Leo Kwan

          If anyone is using Swift 2.+, this will remove any errors for the ‘comps’ variable,

          let comps = cal.components([.Year, .Month, .Day, .Hour, .Minute, .Second], fromDate: NSDate())

      • Or

        i do also have lot of issues because of version 8, i also change to .NSCalendarUnitMinute
        and now its not recognize it

  • Simone Gerardini

    Hi, is it possible to start the steps counter from 0?
    Thank you

    • Jobs

      You can reset the pedometer data

  • Nisha

    Can u provide the sample code for this project

  • adam

    can you provide an updated version for this in ios 9. or a similar application please?

  • Prajin Palangsantikul
/* ]]> */