4

When I setup an HKObserverQuery, the update handler always gets immediately called (something I didn't expect). It also gets called when I add data points through Health.app, as you would expect. I am tending to think I am not doing something right with the completion handler, but the docs are fairly sparse on what is supposed to happen here.

Question: Below is basically what I'm doing. Is this expected behavior, or am I missing something?

    func listenForUpdates() {
        let bodyMassType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass)
        let updateHandler: (HKObserverQuery!, HKObserverQueryCompletionHandler!, NSError!) -> Void = { query, completion, error in
            if !error {
                println("got an update")
                // ... perform a sample query to get the actual data
                completion() // is this the right thing to do?
            } else {
                println("observer query returned error: \(error)")
            }            
        }
        let query = HKObserverQuery(sampleType: bodyMassType, predicate: nil, updateHandler: updateHandler)
        healthStore?.executeQuery(query)
    }

Edit: discovered completion handler should only be called when there wasn't an error, so moved into the !error block. An error is present when the app is not authorized.

Rui Peres
  • 25,741
  • 9
  • 87
  • 137
jaydfwtx
  • 123
  • 1
  • 7

1 Answers1

8

Yes, this is expected behavior. The update handler will always be called on first execution so that you can use it to fetch your initial data (from your sample query, anchored object query, etc) and populate your UI.

The completion handler is only necessary if you intend to use background delivery, it informs HealthKit that you have received and processed the data you need so that HealthKit knows to stop launching your app in the background. If you have not registered your app for background delivery, then the completion handler is essentially a no-op and you don't need to worry about it.

jrushing
  • 878
  • 1
  • 8
  • 11
  • Justin, thanks for the response here. Much appreciated. – jaydfwtx Jun 24 '14 at 04:47
  • Hey Justin. You seem to know your way around Healthkit. In the example provided by @jaydfwtx what is missing to add background support ? Typically, I want to get notifications when the app is in background (or killed). – Marcel Falliere Jul 07 '14 at 13:01
  • Look at HKHealthStore.enableBackgroundDeliveryForType. You enable background delivery, and then do an observer query. – jaydfwtx Jul 09 '14 at 03:01
  • Have you had any issues with enableBackgroundDeliveryForType? On my 4s it's working perfectly, but on my 5s I'm only periodically getting updates on changes to the Health data I'm observing. – bmueller Aug 09 '14 at 22:31
  • @jaydfwtx Are either of you able to get the observer query to fire reliably when your app is in the background? I only get them for a few seconds after backgrounding the app. They seem to only reliably arrive when the app is foregrounded again. [Here](https://devforums.apple.com/message/1027655#1027655) is a devforums post where others seem to be having similar issues. – Sebastian Celis Aug 21 '14 at 21:59
  • @SebastianCelis I put my HK project aside for the past couple of months, so I can't really comment on how the latest beta is behaving. – jaydfwtx Aug 26 '14 at 22:44
  • should completion callback be called asynchronously if the stuff in "// ... perform a sample query to get the actual data" is asynchronous? – moger777 Jan 11 '16 at 21:12
  • You should be able to call the completion handler from whatever thread you like, so long as it is invoked after you have finished processing the results – jrushing Jan 29 '16 at 00:43
  • in the provided code in the question above, can someone help me out with providing the "sample query to get the actual data" please. – Mike Simz Jun 01 '16 at 00:48
  • Does anybody have a open source sample project for this. I am unable to get the updates – Moaz Khan Dec 07 '17 at 06:32
  • @jrushing. Do you have information on the consequences if we don't call completion() at all? – Ashok May 30 '18 at 14:02
  • @jrushing. Got it. From apple "You must call this block as soon as you are done processing the incoming data. Calling this block tells HealthKit that you have successfully received the background data. If you do not call this block, HealthKit continues to attempt to launch your app using a back off algorithm. If your app fails to respond three times, HealthKit assumes that your app cannot receive data, and stops sending you background updates." Source: https://developer.apple.com/documentation/healthkit/hkobserverquerycompletionhandler – Ashok May 30 '18 at 14:03