Search code examples
iosswifthealthkit

Get the latest (most recent) Step value from HealthKit (HKStatistics)


I want to get the very last (aka recent) value of a Health(Kit) App entry. For example the step value from the latest HKSource entry.

I thought that would be working with the HKStatisticsOptions.discreteMostRecent attribute in the query building.

Current result

The code works fine, no error. My statistics has the correct start and end date (if only one value is available, start and end date is the same).

The problem is that the statistics.sources list is always nil like the statistics.mostRecentQuantity() returns also nil.

All not HKSource related sum operations sumQuantity() work without any problem.

Other Stackoverflow posts

I would try the idea with using a query with limit 1 and a sort description from this post, but I need to show other historical values in a detail view too. That's why I thought, that I could request just a date frame of quantities, use the latest one as my "last" and all others for my history table view.

Code

func requestMeasurements(completion: @escaping (HKStatistics?, AppError?) -> Void)
    {
        let healthStore = HKHealthStore()

        // Check if HK is available.
        guard HKHealthStore.isHealthDataAvailable() else
        {
            completion(nil, AppError.healthInformationNotAvailable)
            return
        }

        // Check if HK information is available
        guard let quantitiyType = HKQuantityType.quantityType(forIdentifier: .stepCount) else
        {
            completion(nil, AppError.requestedHealthDataTypeNotAvailable)
            return
        }

        let typeSet: Set = [quantitiyType]

        // Request user access to HK and especially this type
        healthStore.requestAuthorization(toShare: nil, read: typeSet)
        { success, error in

            // Ensure that the app has the required access
            if success == false
            {
                print(error?.localizedDescription ?? "<no error description>")
                completion(nil, AppError.noAccessToRequestedInformation)
                return
            }

            // Build query
            let now = Date()
            let lastSync = Calendar.current.startOfDay(for: now)
            let prediction = HKQuery.predicateForSamples(withStart: lastSync, end: now, options: .strictStartDate)

            let query = HKStatisticsQuery(quantityType: quantitiyType, quantitySamplePredicate: prediction, options: HKStatisticsOptions.discreteMostRecent)
            { _, statistics, error in
                // Check for error.
                if let _error = error
                {
                    print("An error occured: \(_error.localizedDescription)")
                    completion(nil, AppError.requestingFailed)
                    return
                }

                // Check if statistics are available.
                guard let _statistics = statistics else
                {
                    completion(nil, AppError.requestingFailed)
                    return
                }

                completion(_statistics, nil)
            }

            // Execure query
            healthStore.execute(query)
        }

Solution

  • If you want to use just quantities, etc. Just use the HKSampleQuery instead of the HKStatisticsQuery.

    After that, you just have to cast the result list of HKSample to a [HKQuantitySample].

    Now you have the start and end date but also the quantity.