swift - Healthkit HKAnchoredObjectQuery in iOS 9 not returning HKDeletedObject -
i excited learn apple added tracking of deletes in healthkit in ios 9. set test project try out. unfortunately, while can new data fine, not getting deleted objects in callbacks.
i have functioning hkanchoredobjectquery tracks hkqueryanchor , gives me new hksamples whenever add bloodglucose quantity healthkit via health app. when delete same quantity , re-run app hkdeletedobject empty. add , delete @ same time. seems no matter do, hkdeletedobject array empty. additions work fine (only getting added samples since last anchor).
here code. 2 files. recreate project make new swift project, give healthkit entitlement, , copy these in. (note: when run it, 1 update each run if make changes in healthkit have stop , restart app test callbacks.)
this healthkit client:
// // 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 not available on 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){ 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){ 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() } }
this view:
// // 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])! s in deleted!{ msg += s + "\n" } } if (added?.count > 0) { msg += "added: " 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 resources can recreated. } }
note: know apple recommends set using hkobserverquery. did way in xamarin project , behavior same (no hkdeletedobjects getting sent). when trying out swift left out hkobserverquery simplicity.
remove predicate (predicate: nil) when instantiate query , you'll see more results, including deleted results. first time run (before hkqueryanchor has been saved) you'll results may want filter those; subsequent execution of query use saved anchor you'll see changes since saved anchor.
you want set updatehandler property on query before executing. set query run continuously in background calling update handler whenever there changes (adds or deletes). code near end of getglucosesinceanchor(...) looks like
... let anchoredquery = hkanchoredobjectquery(type: sampletype, predicate: nil, anchor: hkanchor, limit: int(maxresults), resultshandler: onanchorqueryresults) anchoredquery.updatehandler = onanchorqueryresults healthkitstore?.executequery(anchoredquery) ...
Comments
Post a Comment