HealthKit 查询游泳泳姿/每圈风格

HealthKit query for swimming strokes / style per lap

我设法查询了游泳泳姿,但它只是累计总和。

private func querySwimStrokeCount(for sample: HKSample) {
    let strokeCount = HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier.swimmingStrokeCount)!
    let sampleDate = HKQuery.predicateForSamples(withStart: sample.startDate, end: sample.endDate, options: [])
    
    let query = HKStatisticsQuery(quantityType: strokeCount,
                                  quantitySamplePredicate: sampleDate,
                                  options: .cumulativeSum) { (query, statisticsOrNil, errorOrNil) in
        
        guard let statistics = statisticsOrNil else {
            return
        }
        
        let sum = statistics.sumQuantity()
        let strokeCount = sum?.doubleValue(for: HKUnit.count()) ?? 0
        
        DispatchQueue.main.async {
            self.strokeCount = Int(strokeCount)
        }
    }
    
    HKHealthStore().execute(query)
}

现在我的问题是如何获得每圈的划水次数和该圈的泳姿? Apple Health App 显示了这些数据(见屏幕截图),但我不知道如何查询它们。

感谢任何帮助!

您正在使用 HKStatisticsQuery,它仅用于获取聚合数据。

Statistics queries calculate common statistics over the set of matching samples. You can use statistical queries to calculate the minimum, maximum, or average value of a set of discrete quantities, or use them to calculate the sum for cumulative quantities.

获取真实样本HKSampleQuery

You can use sample queries to search for any concrete subclasses of the HKSample class, including HKCategorySample, HKCorrelation, HKQuantitySample, and HKWorkout objects. The sample query returns sample objects that match the provided type and predicate. You can provide a sort order for the returned samples, or limit the number of samples returned. Other query classes can be used to perform more specialized searches and calculations. For more information, see HKQuery.

HKAnchoredObjectQuery 我更喜欢监视所有更改

Anchored object queries provide an easy way to search for new data in the HealthKit store. An HKAnchoredObjectQuery returns an anchor value that corresponds to the last sample or deleted object received by that query. Subsequent queries can use this anchor to restrict their results to only newer saved or deleted objects. Anchored object queries are mostly immutable. You can assign the query’s updateHandler property after instantiating the object, but you must set all other properties when you instantiate the object. You can’t change them.

这里有一些希望对您的问题有用的代码

var anchor = self.getAnchorFor() // My private method to get the latest anchor for a type of HKEntry
let sampleType = HKObjectType

self.anchoredQuery = HKAnchoredObjectQuery(type: sampleType, predicate: nil, anchor: anchor, limit: HKObjectQueryNoLimit) { (query, samplesOrNil, deletedObjectsOrNil, newAnchor, errorOrNil) in
    
    guard let addedObjects = samplesOrNil, let deletedObjects = deletedObjectsOrNil else {
        // Handle the error here.
        return;
    }
    
    anchor = newAnchor
    self.storeNewAnchor() // My private method to store the latest anchor for a type of HKEntry
    
    for obj in addedObjects {
        if let sampleObj = obj as? HKWorkout{ // HKWorkout is just an example for a typ
            let uuid = sampleObj.uuid.uuidString
            let source = sampleObj.sourceRevision.source.name
            let sourceBundleID = sampleObj.sourceRevision.source.bundleIdentifier
            
            print("object added: " + uuid)
            print("source: " + source + " bundleID: " + sourceBundleID)
        }
    }
    
    for obj in deletedObjects {
        let uuid = obj.uuid.uuidString
        
        print("object deleted: " + uuid)

    }
    
    print("Finished-")
}


// Optionally, add an update handler.
self.anchoredQuery!.updateHandler = { (query, samplesOrNil, deletedObjectsOrNil, newAnchor, errorOrNil) in
    
    guard let addedObjects = samplesOrNil, let deletedObjects = deletedObjectsOrNil else {
        // Handle the error here.
        

        return;
    }
    
    anchor = newAnchor
    self.storeNewAnchor() // My private method to store the latest anchor for a type of HKEntry
    
    for obj in addedObjects {
        if let sampleObj = obj as? HKWorkout{ // HKWorkout is just an example for a typ
            let uuid = sampleObj.uuid.uuidString
            let source = sampleObj.sourceRevision.source.name
            let sourceBundleID = sampleObj.sourceRevision.source.bundleIdentifier

            print("object added: " + uuid)
            print("source: " + source + " bundleID: " + sourceBundleID)

        }
    }
    
    for obj in deletedObjects {
        let uuid = obj.uuid.uuidString
        
        print("object deleted: " + uuid)

    }
    
    print("Update Finished-")
}

// Run the query.
self.healthStore.execute(self.anchoredQuery!)

@incmiko 的回答通过查看 HKSampleQuery 为我指明了正确的方向。但是 his/her 代码对我没有帮助。所以这就是我为获得每圈的笔划风格所做的。

private func querySwimStrokes(for sample: HKSample) {
    let sampleType = HKSampleType.quantityType(forIdentifier: .swimmingStrokeCount)!
    let sampleDate = HKQuery.predicateForSamples(withStart: sample.startDate, end: sample.endDate, options: [])
    let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
    
    let query = HKSampleQuery(sampleType: sampleType,
                              predicate: sampleDate,
                              limit: HKObjectQueryNoLimit,
                              sortDescriptors: [sortDescriptor]) { query, samplesOrNil, errorOrNil in
        
        samplesOrNil?.forEach({ sample in
                            
            if let quantitySample = sample as? HKQuantitySample {
                let strokes = quantitySample.quantity.doubleValue(for: HKUnit.count())
                print(strokes)
            }
            
            if let strokeStyleInt = sample.metadata?["HKSwimmingStrokeStyle"] as? Int,
               let strokeStyle = HKSwimmingStrokeStyle(rawValue: strokeStyleInt){
                print(strokeStyle)
            }
        })
    }
    
    HKHealthStore().execute(query)
}