Question

#import "CPPedometerViewController.h"
#import <CoreMotion/CoreMotion.h>

@interface CPPedometerViewController ()

@property (weak, nonatomic) IBOutlet UILabel *stepsCountingLabel;
@property (nonatomic, strong) CMStepCounter *cmStepCounter;
@property (nonatomic, strong) NSOperationQueue *operationQueue;
@property (nonatomic, strong) NSMutableArray *stepsArray;

@end

@implementation CPPedometerViewController

- (NSOperationQueue *)operationQueue
{
    if (_operationQueue == nil)
    {
        _operationQueue = [NSOperationQueue new];
    }
    return _operationQueue;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self QueryExistingStep];


    NSLog( @"steps array = %@", _stepsArray);

}

-(void)QueryExistingStep
{
    //get todays date
    NSDate *now = [NSDate date];
    // get six days ago from today
    NSDate *sixDaysAgo = [now dateByAddingTimeInterval:-6*24*60*60];

    //array to hold step values
    _stepsArray = [[NSMutableArray alloc] initWithCapacity:7];

    //check if step counting is avaliable
    if ([CMStepCounter isStepCountingAvailable])
    {
        //init step counter
        self.cmStepCounter = [[CMStepCounter alloc] init];

        //get seven days before from date & to date.
        for (NSDate *toDate = [sixDaysAgo copy]; [toDate compare: now] <= 0;
             toDate = [toDate dateByAddingTimeInterval:24 * 60 * 60] ) {

            //get day before
            NSDate *fromDate = [[toDate copy] dateByAddingTimeInterval: -1 * 24 * 60 * 60];

            [self.cmStepCounter queryStepCountStartingFrom:fromDate to:toDate toQueue:self.operationQueue withHandler:^(NSInteger numberOfSteps, NSError *error) {
                if (!error) {
                    NSLog(@"queryStepCount returned %ld steps", (long)numberOfSteps);
                    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                        [self updateArrayWithStepCounter:numberOfSteps];
                    }];
                } else {
                    NSLog(@"Error occured: %@", error.localizedDescription);
                }

            }];

        }
    } else {
        // stuffhappens
    }
}

- (void)updateArrayWithStepCounter:(NSInteger)numberOfSteps {

    [_stepsArray addObject:[NSNumber numberWithInteger:numberOfSteps]];
}

@end

I'm looking to have an array full of steps from the past seven days, and then insert them into to a NSinteger for each day. e.g. NSinteger daySeven = 242, NSInteger daySix = 823 ... etc too today.

However the array seems to clear after exiting the updateArrayWithStepCounter method. Any idea on how i could fix this so each number of steps goes into separate NSIntegers also. Thanks, Ryan.

EDIT:

Here is the NSLog output:

2014-01-25 22:51:36.314 Project[6633:60b] steps array = (
)
2014-01-25 22:51:36.332 Project[6633:420f] queryStepCount returned 3505 steps
2014-01-25 22:51:36.334 Project[6633:420f] queryStepCount returned 3365 steps
2014-01-25 22:51:36.335 Project[6633:420f] queryStepCount returned 7206 steps
2014-01-25 22:51:36.337 Project[6633:420f] queryStepCount returned 6045 steps
2014-01-25 22:51:36.339 Project[6633:420f] queryStepCount returned 5259 steps
2014-01-25 22:51:36.342 Project[6633:420f] queryStepCount returned 6723 steps
2014-01-25 22:51:36.344 Project[6633:420f] queryStepCount returned 440 steps

Here is the output shown as suggested. As you can see its definitely getting the values however when it checks the array after running the method its now empty.

Could i be adding it to the array incorrectly?

I hope this is clearer I'm stumped. Thanks

Was it helpful?

Solution

First, what's the output of this?

NSLog(@"steps array = %@", _stepsArray);

When someone ask you something, you should try to reply with the exact information requested, just saying "it says that array is empty" doesn't help, because maybe someone can see something that you don't see in the output.

Said this, I would add some more NSLog around, because it could be that your handler is not called, or not called with the information that you expect.

Use the following, and let us know the output :)

[self.cmStepCounter queryStepCountStartingFrom:fromDate to:toDate toQueue:self.operationQueue withHandler:^(NSInteger numberOfSteps, NSError *error) {
    if (!error) {
        NSLog(@"queryStepCount returned %d steps", numberOfSteps);
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [self updateArrayWithStepCounter:numberOfSteps];
        }];
    } else {
        NSLog(@"Error occured: %@", error.localizedDescription);
    }

}];

EDIT: From the new posted output of the NSLog, I can understand the problem. The fact is that the handler runs asynchronously, it means that you can't just output the array on viewDidLoad, because it runs BEFORE the array received all the values, so you should refactor your code to trigger a method when all the data is ready.

Here a revision of your code that is more readable (removed some useless "copy" call, updated your "for conditions", etc...), now it should be really easy to understand what's going on, and how to perform additional logic.

#import "PYViewController.h"
#import <CoreMotion/CoreMotion.h>

@interface PYViewController ()

@property (weak, nonatomic) IBOutlet UILabel *stepsCountingLabel;
@property (nonatomic, strong) CMStepCounter *cmStepCounter;
@property (nonatomic, strong) NSOperationQueue *operationQueue;
@property (nonatomic, strong) NSMutableArray *stepsArray;

@end

@implementation PYViewController

- (NSOperationQueue *)operationQueue {
    if (_operationQueue == nil) {
        _operationQueue = [NSOperationQueue new];
        _operationQueue.maxConcurrentOperationCount = 1; // process 1 operation at a time, or we could end with unexpected results on _stepsArray
    }
    return _operationQueue;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    [self queryExistingStep];
}

-(void)queryExistingStep {
    // Get now date
    NSDate *now = [NSDate date];

    // Array to hold step values
    _stepsArray = [[NSMutableArray alloc] initWithCapacity:7];

    // Check if step counting is avaliable
    if ([CMStepCounter isStepCountingAvailable]) {
        // Init step counter
        self.cmStepCounter = [[CMStepCounter alloc] init];
        // Tweak this value as you need (you can also parametrize it)
        NSInteger daysBack = 6;
        for (NSInteger day = daysBack; day > 0; day--) {
            NSDate *fromDate = [now dateByAddingTimeInterval: -day * 24 * 60 * 60];
            NSDate *toDate = [fromDate dateByAddingTimeInterval:24 * 60 * 60];

            [self.cmStepCounter queryStepCountStartingFrom:fromDate to:toDate     toQueue:self.operationQueue withHandler:^(NSInteger numberOfSteps, NSError *error) {
                if (!error) {
                    NSLog(@"queryStepCount returned %ld steps", (long)numberOfSteps);
                    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                        [_stepsArray addObject:@(numberOfSteps)];

                        if ( day == 1) { // Just reached the last element, do what you want with the data
                            NSLog(@"_stepsArray filled with data: %@", _stepsArray);
                            // [self updateMyUI];
                        }
                    }];
                } else {
                    NSLog(@"Error occured: %@", error.localizedDescription);
                }                
            }];
        }
    } else {
        NSLog(@"device not supported");
    }
}

@end

OTHER TIPS

What i would do is waiting for the array to get all the needed value and do stuff later. It works for me.

- (void)queryPast6DayStepCounts
{
   NSLog(@"queryPast6DayStepCounts visited!");

  self.past6DaysDailySteps = [[NSMutableArray alloc] initWithCapacity:6];

// past 6 days

for (NSInteger day = 6; day >= 1; day--)
{
    NSDate *fromDate = [self.todayMidnight dateByAddingTimeInterval:-day * 24 * 60 * 60];
    NSDate *toDate = [fromDate dateByAddingTimeInterval:24 * 60 * 60];

    [self.cmStepCounter
     queryStepCountStartingFrom:fromDate to:toDate
     toQueue:[NSOperationQueue mainQueue]
     withHandler:^(NSInteger numberOfSteps, NSError *error)
     {
         if (!error)
         {
                 [self.past6DaysDailySteps addObject:@(numberOfSteps)];
                 if (self.past6DaysDailySteps.count == 6) {
                     [self viewDidFinishQueryPast6DaysData];
                 }

         }
         else
         {
             NSLog(@"Error occured: %@", error.localizedDescription);
         }
     }
     ];

}
 }
 -(void)viewDidFinishQueryPast6DaysData
  {
    NSLog(@"queryPast6DayStepCounts finish! %@", self.past6DaysDailySteps);
   // do other things
 }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top