健康包HKAnchoredObjectQuery在iOS 9不返回HKDeletedObject

我很高兴知道苹果在iOS 9中增加了对HealthKit的删除跟踪。所以我build立了一个testing项目来试用。 不幸的是,虽然我可以得到新的数据,但我没有得到任何删除对象在我的callback。

我有一个能够跟踪HKQueryAnchor的HKAnchoredObjectQuery函数,当我通过Health应用程序向HealthKit添加BloodGlucose数量时,会为我提供新的HKSamples。 但是,当我删除相同的数量,并重新运行应用HKDeletedObject始终是空的。 即使我同时做一个添加和删除。 看来不pipe我做什么,HKDeletedObject数组总是空的。 但是,添加工作正常(只从上次锚点获取添加的样本)。

这是我的代码。 这只是2个文件。 要重新创build项目,只需创build一个新的swift项目,给自己一个HealthKit权利,然后复制这些项目。(注意:运行它时,每次运行只会得到一个更新,所以如果在HealthKit中进行更改,则必须停止重新启动应用程序来testingcallback。)

这是我的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. } } 

注意:我知道Applebuild议使用HKObserverQuery进行设置。 我原本是在Xamarin项目中这样做的,行为是一样的(没有HKDeletedObjects被发送)。 所以当用swift试用时,为了简单,我省略了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) ...