繁体   English   中英

iOS 9中的Healthkit HKAnchoredObjectQuery不返回HKDeletedObject

[英]Healthkit HKAnchoredObjectQuery in iOS 9 not returning HKDeletedObject

我很高兴得知Apple在iOS 9的HealthKit中添加了删除跟踪功能。因此,我建立了一个测试项目来进行尝试。 不幸的是,尽管我可以很好地获取新数据,但在回调中却没有任何删除的对象。

我有一个正常运行的HKAnchoredObjectQuery,它可以跟踪HKQueryAnchor并在通过Health应用程序向HealthKit中添加BloodGlucose量时为我提供新的HKSamples。 但是,当我删除相同数量并重新运行应用程序时,HKDeletedObject始终为空。 即使我同时进行添加和删除。 似乎不管我做什么,HKDeletedObject数组始终为空。 但是添加工作正常(仅从上一个锚点获取添加的样本)。

这是我的代码。 它只有2个文件。 要重新创建项目,只需创建一个新的快速项目,给自己命名HealthKit权利,然后将其复制。(注意:运行该项目时,每次运行仅获得一个更新,因此,如果在HealthKit中进行更改,则必须停止并重新启动应用程序以测试回调。)

这是我的HealthKit客户:

//
//  HKClient.swift
//  HKTest

import UIKit
import HealthKit

class HKClient : NSObject {

    var isSharingEnabled: Bool = false
    let healthKitStore:HKHealthStore? = HKHealthStore()
    let glucoseType : HKObjectType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBloodGlucose)!

    override init(){
        super.init()
    }

    func requestGlucosePermissions(authorizationCompleted: (success: Bool, error: NSError?)->Void) {

        let dataTypesToRead : Set<HKObjectType> = [ glucoseType ]

        if(!HKHealthStore.isHealthDataAvailable())
        {
            // let error = NSError(domain: "com.test.healthkit", code: 2, userInfo: [NSLocalizedDescriptionKey: "Healthkit is not available on this device"])
            self.isSharingEnabled = false
            return
        }

        self.healthKitStore?.requestAuthorizationToShareTypes(nil, readTypes: dataTypesToRead){(success, error) -> Void in
            self.isSharingEnabled = true
            authorizationCompleted(success: success, error: error)
        }
    }

    func getGlucoseSinceAnchor(anchor:HKQueryAnchor?, maxResults:uint, callback: ((source: HKClient, added: [String]?, deleted: [String]?, newAnchor: HKQueryAnchor?, error: NSError?)->Void)!){
        let queryEndDate = NSDate(timeIntervalSinceNow: NSTimeInterval(60.0 * 60.0 * 24))
        let queryStartDate = NSDate.distantPast()
        let sampleType: HKSampleType = glucoseType as! HKSampleType
        let predicate: NSPredicate = HKAnchoredObjectQuery.predicateForSamplesWithStartDate(queryStartDate, endDate: queryEndDate, options: HKQueryOptions.None)
        var hkAnchor: HKQueryAnchor;

        if(anchor != nil){
            hkAnchor = anchor!
        } else {
            hkAnchor = HKQueryAnchor(fromValue: Int(HKAnchoredObjectQueryNoAnchor))
        }

        let onAnchorQueryResults : ((HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?, NSError?) -> Void)! = {
            (query:HKAnchoredObjectQuery, addedObjects:[HKSample]?, deletedObjects:[HKDeletedObject]?, newAnchor:HKQueryAnchor?, nsError:NSError?) -> Void in

            var added = [String]()
            var deleted = [String]()

            if (addedObjects?.count > 0){
                for obj in addedObjects! {
                    let quant = obj as? HKQuantitySample
                    if(quant?.UUID.UUIDString != nil){
                        let val = Double( (quant?.quantity.doubleValueForUnit(HKUnit(fromString: "mg/dL")))! )
                        let msg : String = (quant?.UUID.UUIDString)! + " " + String(val)
                        added.append(msg)
                    }
                }
            }

            if (deletedObjects?.count > 0){
                for del in deletedObjects! {
                    let value : String = del.UUID.UUIDString
                    deleted.append(value)
                }
            }

            if(callback != nil){
                callback(source:self, added: added, deleted: deleted, newAnchor: newAnchor, error: nsError)
            }
        }

        let anchoredQuery = HKAnchoredObjectQuery(type: sampleType, predicate: predicate, anchor: hkAnchor, limit: Int(maxResults), resultsHandler: onAnchorQueryResults)
        healthKitStore?.executeQuery(anchoredQuery)
    }

    let AnchorKey = "HKClientAnchorKey"
    func getAnchor() -> HKQueryAnchor? {
        let encoded = NSUserDefaults.standardUserDefaults().dataForKey(AnchorKey)
        if(encoded == nil){
            return nil
        }
        let anchor = NSKeyedUnarchiver.unarchiveObjectWithData(encoded!) as? HKQueryAnchor
        return anchor
    }

    func saveAnchor(anchor : HKQueryAnchor) {
        let encoded = NSKeyedArchiver.archivedDataWithRootObject(anchor)
        NSUserDefaults.standardUserDefaults().setValue(encoded, forKey: AnchorKey)
        NSUserDefaults.standardUserDefaults().synchronize()
    }
}

这是我的观点:

//
//  ViewController.swift
//  HKTest

import UIKit
import HealthKit

class ViewController: UIViewController {
    let debugLabel = UILabel(frame: CGRect(x: 10,y: 20,width: 350,height: 600))

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view = UIView();
        self.view.backgroundColor = UIColor.whiteColor()


        debugLabel.textAlignment = NSTextAlignment.Center
        debugLabel.textColor = UIColor.blackColor()
        debugLabel.lineBreakMode = NSLineBreakMode.ByWordWrapping
        debugLabel.numberOfLines = 0
        self.view.addSubview(debugLabel)

        let hk = HKClient()
        hk.requestGlucosePermissions(){
            (success, error) -> Void in

            if(success){
                let anchor = hk.getAnchor()

                hk.getGlucoseSinceAnchor(anchor, maxResults: 0)
                    { (source, added, deleted, newAnchor, error) -> Void in
                        var msg : String = String()

                        if(deleted?.count > 0){
                            msg += "Deleted: \n" + (deleted?[0])!
                            for s in deleted!{
                                msg += s + "\n"
                            }
                        }

                        if (added?.count > 0) {
                            msg += "Added: "
                            for s in added!{
                                msg += s + "\n"
                            }
                        }

                        if(error != nil) {
                            msg = "Error = " + (error?.description)!
                        }

                        if(msg.isEmpty)
                        {
                            msg = "No changes"
                        }
                        debugPrint(msg)

                        if(newAnchor != nil && newAnchor != anchor){
                            hk.saveAnchor(newAnchor!)
                        }

                        dispatch_async(dispatch_get_main_queue(), { () -> Void in
                            self.debugLabel.text = msg
                        })
                    }
            }
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

注意:我知道Apple建议使用HKObserverQuery进行设置。 我最初是在Xamarin项目中这样做的,其行为是相同的(没有发送HKDeletedObjects)。 因此,在快速尝试时,为简单起见,我省略了HKObserverQuery。

实例化查询时,删除谓词(谓词:nil),您将看到更多结果,包括已删除的结果。 第一次运行此操作(在保存HKQueryAnchor之前),您将获得所有结果,因此您可能需要做一些过滤这些结果的操作; 但是随后执行查询将使用您保存的锚,因此您将仅看到自该保存的锚以来的更改。

您可能还想在执行之前在查询上设置updateHandler属性。 这会将查询设置为在发生更改(添加或删除)时在后台调用更新处理程序连续运行。 getGlucoseSinceAnchor(...)末尾的代码看起来像

...
let anchoredQuery = HKAnchoredObjectQuery(type: sampleType, predicate: nil, anchor: hkAnchor, limit: Int(maxResults), resultsHandler: onAnchorQueryResults)
anchoredQuery.updateHandler = onAnchorQueryResults
healthKitStore?.executeQuery(anchoredQuery)
...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM