I've found very limited resources on this topic (CMPedometer). I was wondering if anyone here has managed to get this to work properly. My code is fairly simple, and has more than what I'm trying to do. Basically, the step counter does not increment EVERY step a user takes.
It actually is tracking every step the user takes but it updates so slowly and I can't figure out why. I even tried using NSTimer to make a request to update the labels every half a second. I want to try to get the step counter to update as a user takes a step. Here is my code...
#import "ViewController.h"
#import <CoreMotion/CoreMotion.h>
@interface ViewController ()
@property (nonatomic, strong) CMPedometer *pedometer;
@property (nonatomic, weak) IBOutlet UILabel *startDateLabel;
@property (nonatomic, weak) IBOutlet UILabel *endDateLabel;
@property (nonatomic, weak) IBOutlet UILabel *stepsLabel;
@property (nonatomic, weak) IBOutlet UILabel *distanceLabel;
@property (nonatomic, weak) IBOutlet UILabel *ascendedLabel;
@property (nonatomic, weak) IBOutlet UILabel *descendedLabel;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
if ([CMPedometer isStepCountingAvailable]) {
self.pedometer = [[CMPedometer alloc] init];
[NSTimer scheduledTimerWithTimeInterval:0.5f
target:self
selector:@selector(recursiveQuery)
userInfo:nil
repeats:YES];
} else {
NSLog(@"Nothing available");
self.startDateLabel.text = @"";
self.endDateLabel.text = @"";
self.stepsLabel.text = @"";
self.distanceLabel.text = @"";
self.ascendedLabel.text = @"";
self.descendedLabel.text = @"";
}
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.pedometer startPedometerUpdatesFromDate:[NSDate date]
withHandler:^(CMPedometerData *pedometerData, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"data:%@, error:%@", pedometerData, error);
});
}];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.pedometer stopPedometerUpdates];
}
- (NSString *)stringWithObject:(id)obj {
return [NSString stringWithFormat:@"%@", obj];
}
- (NSString *)stringForDate:(NSDate *)date {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateStyle = NSDateFormatterShortStyle;
formatter.timeStyle = NSDateFormatterShortStyle;
return [formatter stringFromDate:date];
}
- (void)queryDataFrom:(NSDate *)startDate toDate:(NSDate *)endDate {
[self.pedometer queryPedometerDataFromDate:startDate
toDate:endDate
withHandler:
^(CMPedometerData *pedometerData, NSError *error) {
NSLog(@"data:%@, error:%@", pedometerData, error);
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
NSLog(@"Error = %@",error.userInfo);
self.startDateLabel.text = @"";
self.endDateLabel.text = @"";
self.stepsLabel.text = @"";
self.distanceLabel.text = @"";
self.ascendedLabel.text = @"";
self.descendedLabel.text = @"";
} else {
self.startDateLabel.text = [self stringForDate:pedometerData.startDate];
self.endDateLabel.text = [self stringForDate:pedometerData.endDate];
self.stepsLabel.text = [self stringWithObject:pedometerData.numberOfSteps];
self.distanceLabel.text = [NSString stringWithFormat:@"%.1f[m]", [pedometerData.distance floatValue]];
self.ascendedLabel.text = [self stringWithObject:pedometerData.floorsAscended];
self.descendedLabel.text = [self stringWithObject:pedometerData.floorsDescended];
}
});
}];
}
- (void)recursiveQuery {
NSDate *to = [NSDate date];
NSDate *from = [to dateByAddingTimeInterval:-(24. * 3600.)];
[self queryDataFrom:from toDate:to];
}
Thanks in advance for any feedback!
EDIT
It seems the appropriate method to use for live updates is the following..
- (void)liveSteps {
[self.pedometer startPedometerUpdatesFromDate:[NSDate date]
withHandler:^(CMPedometerData *pedometerData, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Steps %@",pedometerData.numberOfSteps);
});
}];
}
However, even this is severely delayed. Does anyone have any idea how to use this properly to essentially update as the user takes a step?
I can only confirm your findings. I also wanted to get "true" realtime information. As it seems at this point, the API is not capable of this; even by forcing the updates into a queue, sync, async, etc.
For references and others with this question, here is the code I use based on Swift 3 and Xcode 8.2. I simply apply this portion of code in the concerned viewcontroller, after checking the CMPedometer.isStepCountingAvailable().
As you can see, I've included a small animation to update the UILabel in a more fluid manner.
// Steps update in near realtime - UILabel
self.pedoMeter.startUpdates(from: midnightOfToday) { (data: CMPedometerData?, error) -> Void in
DispatchQueue.main.async(execute: { () -> Void in
if(error == nil){
self.todaySteps.text = "\(data!.numberOfSteps)"
// Animate the changes of numbers in the UILabel
UILabel.transition(with: self.todaySteps,
duration: 0.50,
options: .transitionCrossDissolve,
animations: nil,
completion: nil)
}
})
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With