HKObserverQuery randomly called twice in a row
Asked Answered
C

2

5

I have an issue I'm trying to solve, I've setup an HKObserveryQuery, which works great and gathers new data for me.

The issue however is that sometimes when I go back to the Health app and delete an item after I've manually added it to the Health app, I notice the HKObserverQuery I've set up fires two times very closely together, which I'm trying to solve because I use this observer to later upload some data, and I don't want a duplicate.

I'd appreciate any help offered. Code:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [self setup];

    return YES;
}

- (void)setup
{
    if ([HKHealthStore isHealthDataAvailable])
    {
        self.healthStore = [[HKHealthStore alloc]init];

        NSSet *readTypes = [NSSet setWithObject:[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate]];

        [self.healthStore requestAuthorizationToShareTypes:nil
                                                 readTypes:readTypes
                                                completion:^(BOOL success, NSError *error)
         {
             if (!error && success)
             {
                 [self observeHR];

                 [self.healthStore enableBackgroundDeliveryForType:
                 [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate]
                 frequency:HKUpdateFrequencyImmediate withCompletion:^(BOOL success, NSError *error){}];
             }
         }];
    }
}

- (void)observeHR
{
    HKObserverQuery *query = [[HKObserverQuery alloc]initWithSampleType:[HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate]
                        predicate:nil
    updateHandler:^(HKObserverQuery *query, HKObserverQueryCompletionHandler completionHandler, NSError *error)
    {
        if (!error)
        {   
            // Randomly called twice *VERY* close together
            NSLog(@"Query");
            [self queryWithCompletionHandler:completionHandler];
        }
        else
        {
            if (completionHandler)
            {
                completionHandler();
            }
        }
    }];

    [self.healthStore executeQuery:query];
}

Console output, notice the times: This occurs when only deleting one item from the Health app, which is incorrect.

2014-12-29 16:50:20.121 TestApp[174:5674] Query
2014-12-29 16:50:20.124 TestApp[174:5674] Query
Cholecystitis answered 30/12, 2014 at 2:30 Comment(0)
C
5

I believe I've now fixed the issue by setting a BOOL flag to prevent a second bogus HKObserverQuery to be called, and eliminating duplicate processing for no reason. Code:

- (void)observeHR
{
    HKObserverQuery *query = [[HKObserverQuery alloc]initWithSampleType:[HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate]
                        predicate:nil
    updateHandler:^(HKObserverQuery *query, HKObserverQueryCompletionHandler completionHandler, NSError *error)
    {
        if (!self.queryInProgress)
        {
            self.queryInProgress = YES;

            if (!error)
            {
                [self queryWithCompletionHandler:completionHandler];
            }
            else
            {
                self.queryInProgress = NO;

                if (completionHandler)
                {
                    completionHandler();
                }
            }
        }
        else
        {
            NSLog(@"Query already in progress");
        }
    }];

    [self.healthStore executeQuery:query];
}
Cholecystitis answered 30/12, 2014 at 5:54 Comment(2)
I am curious why this is needed though. I am experiencing the same thing and I would like to avoid any undue load on my storage and processing system. Did you find the route cause of it double firing?Schechter
hey you any resolution for this double query firing issue. I am facing same issue in my case. Please share asap.Potentate
B
5

You should not design a system that relies on the updateHandler of HKObserverQuery firing exactly once for any particular event. Treat invocations of updateHandler simply as an indication that any number of samples matching the predicate may have been added or deleted. It is up to you to perform a query to discover what changed. If for instance you are interested in only new samples matching a predicate, you could use an HKAnchoredObjectQuery to retrieve just the samples you have not processed yet.

Barns answered 31/12, 2014 at 17:45 Comment(1)
Sure, I agree. But I am curious as to why this is double firing.Schechter

© 2022 - 2024 — McMap. All rights reserved.