How to access the Step Counter and Pedometer Data in iOS 9


Since iOS 8 we can access data from the motion co-processors in iOS on compatible devices. One of those goodies is a pedometer (or step counter). With this new Core Motion class we can check how far we’ve travelled, how many steps we’ve taken, and even – since iOS 9 – how many flights of stairs we’ve walked up or down.

We can track live data as well as check the last seven days worth of data, both of which is only reliably available on devices with a motion co-processor.

Let’s see how many steps we’ve taken today!

Prep Work

We’ll be looking at two classes of the Core Motion framework: CMPedometer (the actual pedometer class), and CMPedometerData (properties returned from the pedometer).

To start with, we need to hold a reference to that pedometer so we can start and stop live tracking, or readout past data. I’ll do this with a custom initialiser and a property called pedometer. We also need to import the Core Motion framework so Xcode knows what we’re walking about:

@import CoreMotion;

// ...

- (CMPedometer *)pedometer {
    if (!_pedometer) {
        _pedometer = [[CMPedometer alloc]init];

That’s really all the setup we need.

Live Step Counting

To start receiving live updates from the pedometer, we’ll call the startPedometerUpdatesFromDate method. We need to provide an NSDate (such as “right now”). Part of the method signature is a handler block, in which any live updates are returned when available. This block is called for every new update:

- (IBAction)startTracking:(id)sender {
    // start live tracking
    [self.pedometer startPedometerUpdatesFromDate:[NSDate date] withHandler:^(CMPedometerData * _Nullable pedometerData, NSError * _Nullable error) {
        // this block is called for each live update
        [self updateLabels:pedometerData];

It can take a few moments for the pedometer to kick in and deliver data. Several times per minute we’ll receive an update on the current tracking session.

In this block we’re given an error object in case something went wrong, and a CMPedometerData object with several interesting properties:

  • numberOfSteps
  • distance (in meters)
  • currentPace (in seconds per meter)
  • currentCadence (in steps per second)
  • floorsAscended
  • floorsDecended

In my sample app I’m going to update a series of labels – but only when the actual item is available on the current hardware. Lucky for us there are singletons available with which we can check this:

- (void)updateLabels:(CMPedometerData *)pedometerData {
    NSNumberFormatter *formatter = [[NSNumberFormatter alloc]init];
    formatter.maximumFractionDigits = 2;
    // step counting
    if ([CMPedometer isStepCountingAvailable]) {
        self.stepsLabel.text = [NSString stringWithFormat:@"Steps walked: %@", [formatter stringFromNumber:pedometerData.numberOfSteps]];
    } else {
        self.stepsLabel.text = @"Step Counter not available.";
    // distance
    if ([CMPedometer isDistanceAvailable]) {
        self.distanceLabel.text = [NSString stringWithFormat:@"Distance travelled: \n%@ meters", [formatter stringFromNumber:pedometerData.distance]];
    } else {
        self.distanceLabel.text = @"Distance estimate not available.";
    // pace
    if ([CMPedometer isPaceAvailable] && pedometerData.currentPace) {
        self.paceLabel.text = [NSString stringWithFormat:@"Current Pace: \n%@ seconds per meter", [formatter stringFromNumber:pedometerData.currentPace]];
    } else {
        self.paceLabel.text = @"Pace not available.";
    // cadence
    if ([CMPedometer isCadenceAvailable] && pedometerData.currentCadence) {
        self.cadenceLabel.text = [NSString stringWithFormat:@"Cadence: \n%@ steps per second", [formatter stringFromNumber: pedometerData.currentCadence]];
    } else {
        self.cadenceLabel.text = @"Cadence not available.";
    // flights climbed
    if ([CMPedometer isFloorCountingAvailable] && pedometerData.floorsAscended) {
        self.flightsUpLabel.text = [NSString stringWithFormat:@"Floors ascended: %@", pedometerData.floorsAscended];
    } else {
        self.flightsUpLabel.text = @"Floors ascended not available.";
    if ([CMPedometer isFloorCountingAvailable] && pedometerData.floorsDescended) {
        self.flightsDownLabel.text =[NSString stringWithFormat:@"Floors descended: %@", pedometerData.floorsDescended];
    } else {
        self.flightsDownLabel.text = @"Floors descended not available.";

Don’t be scared by such a long method: it simply checks if a property is available, and when it is update the label accordingly. It’s so long because we have 6 properties to check. Most values deliver a really long floating point number, so I’m using a number formatter to curb this to two digits (much easier on the eye).

If we no longer want to receive updates, we can call the stopPedometerUpdates on our pedometer:

- (IBAction)stopTracking:(id)sender {
    // stop live tracking
    [self.pedometer stopPedometerUpdates];

One thing to note here is that when our app moves to the background, or the user turns off the device screen, these live updates will stop temporarily. It’s not like the CLLocationManager that delivers updates even when the app is not in the foreground.

Hence, live tracking steps isn’t that big a pleasure after all. Besides, it’s cumbersome having to switch it on before we want to count steps.

Lucky for us, Apple have implemented something even cooler:

Accessing past data

One great thing of the CMPedometer class is that no matter if we’ve started it for live updates, it keeps any steps from the last seven days in a cache we can access much faster. That’s how the Health App does it on iOS, and the plethora of step counting apps on the App Store.

All we need is a start date and an end date, with which we can call a very similar pedometer method named queryPedometerFromDate:toDate. Again we’ll get a handler block with all the properties I’ve mentioned above, albeit without the cadence and pace properties (because they only make sense for live updates):

- (IBAction)queryPedometer:(id)sender {
    // retrieve data between dates
    [self.pedometer queryPedometerDataFromDate:self.startDate toDate:self.endDate withHandler:^(CMPedometerData * _Nullable pedometerData, NSError * _Nullable error) {
        // historic pedometer data is provided here
        [self presentPedometerData:pedometerData];

This handler block is only called once. Note that if you want to grab data for an entire 24 hour period, you may need to normalise your NSDates (i.e. start on November 1st at 00:00:00, and end on November 1st at 23:59:59).

Have fun tracking your steps – past and present 😉

Demo Project

I’ve put a demo project together that shows how this works:

Further Reading

One thought on “How to access the Step Counter and Pedometer Data in iOS 9

Leave a Reply