Ben Dodson

Freelance iOS, Apple Watch, and Apple TV Developer

HKHealthStore Extension, deleteSamplesOfType

Following on from my post yesterday about the broken implementation of the HKHealthStore method deleteObjectsOfType:predicate:withCompletion:, I’ve put together a gist which provides a fixed method that works with HKSampleType objects; deleteSamplesOfType:predicate:withCompletion:

import Foundation
import HealthKit

extension HKHealthStore {
    
    func deleteSamplesOfType(sampleType: HKSampleType, predicate: NSPredicate, withCompletion completion: (success: Bool, count: Int, error: NSError?) -> Void) {
        
        let query = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: 0, sortDescriptors: nil) { (query, results, error) -> Void in
            
            if let _ = error {
                completion(success: false, count: 0, error: error)
                return
            }
            
            if let objects = results {
                if objects.count == 0 {
                    completion(success: true, count: 0, error: nil)
                } else {
                    self.deleteObjects(objects, withCompletion: { (success, error) -> Void in
                        completion(success: error == nil, count: objects.count, error: error)
                    })
                }
            } else {
                completion(success: true, count: 0, error: nil)
            }

        }
        self.executeQuery(query)
    }
    
}

It simply uses the NSPredicate within a HKSampleQuery in order to find any objects that match the HKSampleType and then deletes them with the HKHealthStore method deleteObjects:withCompletion: - this correctly ensures that you are only deleting objects that match both the predicate and type.

By way of example, this simply extends HKHealthStore so you can do something like this:

let date = NSDate()

let predicate = HKQuery.predicateForSamplesWithStartDate(date.beginningOfDay(), endDate: NSDate().endOfDay(), options: .None)

let stepType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)!
healthStore.deleteSamplesOfType(stepType, predicate: predicate, withCompletion: { (success, count, error) -> Void in
    NSLog("deleted \(count) step objects: \(error)")
    let stepQuantity = HKQuantity(unit: HKUnit.countUnit(), doubleValue: 9800)
    let stepSample = HKQuantitySample(type: stepType, quantity: stepQuantity, startDate: date, endDate: date)
    self.healthStore.saveObject(stepSample) { (success, error) -> Void in
    }
})


let flightsType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierFlightsClimbed)!
healthStore.deleteSamplesOfType(flightsType, predicate: predicate, withCompletion: { (success, count, error) -> Void in
    NSLog("deleted \(count) flight objects: \(error)")
    let flightsQuantity = HKQuantity(unit: HKUnit.countUnit(), doubleValue: 15)
    let flightsSample = HKQuantitySample(type: flightsType, quantity: flightsQuantity, startDate: date, endDate: date)
    self.healthStore.saveObject(flightsSample) { (success, error) -> Void in
    }
})

As a reminder, you can file a duplicate of (rdar://22977320) if you’d like to see the original bug fixed but in the meantime the above should allow you to carry on with your HealthKit app without worrying about deleting other data.

A simple Audio Recorder controller in Swift (for iPhone) » « HealthKit Radar 22977320