0

I wrote a code to get heart rate values from Health kit. The code is working fine but when the new heart values are updated in Health kit. I have to come to main screen and then multitask my app to get the updated results. What my aim is to get the updated result on my app without reopening or multitasking it, please help as I am new to iOS development. My code:-

  -(void)get_heartRates
{

//code to get the updated heart beats

HKSampleType *sampleType =
[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];

HKObserverQuery *query =
[[HKObserverQuery alloc]
 initWithSampleType:sampleType
 predicate:nil
 updateHandler:^(HKObserverQuery *query,
                 HKObserverQueryCompletionHandler completionHandler,
                 NSError *error) {

     if (error) {


         NSLog(@"error occured while setting observer. %@ ",
               error.localizedDescription);
         abort();
     }

     // Take whatever steps are necessary to update your app's data and UI
     // This may involve executing other queries


     [self executeAnchoredQuery];

     // If you have subscribed for background updates you must call the completion handler here.
     // completionHandler();

 }];

[self.healthStore executeQuery:query];
 }

-(void)executeAnchoredQuery
{

NSDate *startDate1 = [NSDate distantPast];
NSPredicate *Predicate = [HKQuery     predicateForSamplesWithStartDate:startDate1 endDate:[NSDate date] options:HKQueryOptionStrictEndDate];
HKSampleType *object = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];

sum_Of_HeartRates=0.0;

HKAnchoredObjectQuery  *heartQuery = [[HKAnchoredObjectQuery alloc] initWithType:object predicate:Predicate anchor:self.lastAnchor limit:0 resultsHandler:^(HKAnchoredObjectQuery *query, NSArray<HKSample *> *sampleObjects, NSArray<HKDeletedObject *> *deletedObjects, HKQueryAnchor *newAnchor, NSError *error) {

    NSLog(@"Sample counts:%ld",sampleObjects.count);
    for(int i=0;i<(int)sampleObjects.count;i++)
    {

        HKQuantitySample *sample = (HKQuantitySample *)[sampleObjects objectAtIndex:i];
        HKQuantity *quantity = sample.quantity;
        double bpm_Values= [quantity doubleValueForUnit:[HKUnit unitFromString:@"count/min"]];
        sum_Of_HeartRates=sum_Of_HeartRates+bpm_Values;

    }
    avg_heartBeats=sum_Of_HeartRates/(int)sampleObjects.count;
}];

[heartQuery setUpdateHandler:^(HKAnchoredObjectQuery *query, NSArray<HKSample *> *SampleArray, NSArray<HKDeletedObject *> *deletedObjects, HKQueryAnchor *Anchor, NSError *error) {

    HKQuantitySample *sample = (HKQuantitySample *)[SampleArray objectAtIndex:0];
    HKQuantity *quantity = sample.quantity;
    new_Updated_Data =[quantity doubleValueForUnit:[HKUnit unitFromString:@"count/min"]];
    NSLog(@"new quantity:%f",new_Updated_Data);
}];

[self.healthStore executeQuery:heartQuery];
NSLog(@"updated data %f",new_Updated_Data);


NSLog(@"%f", avg_heartBeats);

 }

1 Answers1

0

See if the following code could help you...

 HKSampleType *sampleType =
    [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];

    HKObserverQuery *query =
    [[HKObserverQuery alloc]
     initWithSampleType:sampleType
     predicate:nil
     updateHandler:^(HKObserverQuery *query,
                     HKObserverQueryCompletionHandler completionHandler,
                     NSError *error) {

         if (error) {


             NSLog(@"error occured while setting observer. %@ ",
                   error.localizedDescription);
             abort();
         }

         // Take whatever steps are necessary to update your app's data and UI
         // This may involve executing other queries


[self executeAnchoredQuery];

         // If you have subscribed for background updates you must call the completion handler here.
         // completionHandler();

     }];

    [self.healthStore executeQuery:query];

and then the function where you write you anchoredQuery code, this may give you an idea of the code flow :

-(void)executeAnchoredQuery
{
HKSampleType *sampleType =
[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];

HKAnchoredObjectQuery *query =
[[HKAnchoredObjectQuery alloc]
 initWithType:sampleType
 predicate:nil
 anchor:self.anchor
 limit:HKObjectQueryNoLimit
 resultsHandler:^(HKAnchoredObjectQuery * _Nonnull query,
                  NSArray<__kindof HKSample *> * _Nullable sampleObjects,
                  NSArray<HKDeletedObject *> * _Nullable deletedObjects,
                  HKQueryAnchor * _Nullable newAnchor,
                  NSError * _Nullable error) {

     if (error != nil) {
         // Add proper error handling here...
         NSLog(@"*** Unable to query for step counts: %@ ***",
               error.localizedDescription);
         abort();
     }

     // Process the results...
     self.anchor = newAnchor;

     for (HKQuantitySample *sample in sampleObjects) {
         [self addStepCountSample:sample];
     }

     for (HKDeletedObject *sample in deletedObjects) {
         [self removeStepCountSample:sample];
     }

     NSLog(@"Done!");
 }];

[self.healthStore executeQuery:query];

}

Please go through apple developer docs for further details.

Ujjwal Khatri
  • 716
  • 1
  • 6
  • 19
  • Yes, but are we getting and storing the queried data there is no NSArray or Dictionary? – DEEP PRADHAN 12BIT0052 Mar 29 '16 at 09:07
  • no observer query will notify you of the changes, and as you can see in the commented lines in code, you can execute other queries to fetch the data. see the comment '// This may involve executing other queries' – Ujjwal Khatri Mar 29 '16 at 09:09
  • Hey Ujjwal, I am still facing the issue. In the above code I used HKAnchoredQuery, its giving the correct output but I need to multitask between main screen and app to get the updated heart rate but what I want my app to be opened and update the heart rate. – DEEP PRADHAN 12BIT0052 Mar 30 '16 at 09:04
  • do you mean that you want to perform the fetching asynchronously?? – Ujjwal Khatri Mar 30 '16 at 09:54
  • Yes without getting my app to multitask just i want live data every time, I had updated my code above that will give perfect output but I need to multitask my app every time to get updated value from Health kit. What should I do to solve this? – DEEP PRADHAN 12BIT0052 Mar 30 '16 at 10:04
  • can you use dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ }); – Ujjwal Khatri Mar 30 '16 at 10:21
  • hmm i am not sure. you can first try to keep the whole code in this, if it doesn't work then you can put that code where you are using anchoredquery. Just try. – Ujjwal Khatri Mar 30 '16 at 10:27
  • Tried both not working. To get the updated value I had to get back to main screen and come back up to my app via multitasking, which I dont want to do. http://stackoverflow.com/questions/32300247/access-workout-data-even-when-apple-watch-screen-turn-off, dont know how he got the solution? – DEEP PRADHAN 12BIT0052 Mar 30 '16 at 10:50
  • in the above link he has just used the anchoredQuery being executed every 5 second using NSTimer, which we are not doing in our case. the thing is simple observer query is called whenever there is a change in health data related to that particular parameter. so you can put login as per your requirement. even if you fetch the results on main thread, it should not take much time because the fetch is local not from server. – Ujjwal Khatri Mar 30 '16 at 11:01
  • yes exactly, then how to solve my issue :(. Even I want to get updated heart rate as soon the heart rate is updated in Health Kit? Using timer can solve my issue? – DEEP PRADHAN 12BIT0052 Mar 30 '16 at 11:05
  • That only i am saying, by setting up observer query you can be notifier of any change in heartratre data and then in that block you can call you anchoredquery or any other whichever you want. check this link for your reference. http://stackoverflow.com/questions/26375767/healthkit-background-delivery-when-app-is-not-running/35073904#35073904 – Ujjwal Khatri Mar 30 '16 at 11:12
  • Inside HKObserverQuery use HKAnchoredQuery? Then what about the timer part? – DEEP PRADHAN 12BIT0052 Mar 30 '16 at 11:17
  • why do you need timer? your observer query will anyways notify you whenever there is change in heartrate data. – Ujjwal Khatri Mar 30 '16 at 11:45
  • Yes, I thinking to do it but I am confused to how to add HKAnchored in Observer? – DEEP PRADHAN 12BIT0052 Mar 30 '16 at 11:46
  • write your anchoreQuery code in place of "// This may involve executing other queries" this. – Ujjwal Khatri Mar 30 '16 at 11:53
  • Then there are two query for both, which one to execute then? – DEEP PRADHAN 12BIT0052 Mar 30 '16 at 12:01
  • both observerQuery and anchoredQuery to be executed. Execute observer query to setup observing the changes and anchored query to fetch the data. anchored query code must be called from within the observer query. Have you read the apple docs completely before trying on this? – Ujjwal Khatri Mar 30 '16 at 12:15
  • Yes I read, but I am not getting what logic to put to check to observe the changes came in HKObserver – DEEP PRADHAN 12BIT0052 Mar 30 '16 at 12:22
  • no changes come in hkobserverquery, it is just like you will get the control in that block and then whatever query you want to execute you can whether anchoredQuery or any other. HKObserverQuery will just give you control in that block whenever there is any change in data, it doen't give you any data. – Ujjwal Khatri Mar 30 '16 at 12:29
  • Haha... i think its a long discussion. you must do it now. :) :) Try, you will get it. :) – Ujjwal Khatri Mar 30 '16 at 12:33
  • yes i have used observerQuery but not with anchored, anyways that doesn't matter. just that you should get the control. Please go through the docs and this link : http://stackoverflow.com/questions/26375767/healthkit-background-delivery-when-app-is-not-running/35073904#35073904. I have changed the code in answer too. please check it. – Ujjwal Khatri Mar 30 '16 at 12:40
  • 1
    Hey Ujjwal thanks :). Now I had executed the stuffs. you can see in the similar manner. Still I ha d to bring the app to the background and again to the foreground to get all the new heart rates. I edited the code above please help. I dont know why I am doing multitasking it. – DEEP PRADHAN 12BIT0052 Mar 30 '16 at 13:13