Health Kit: How to set 'totalEnergyBurned' for workout? - swift

Today I worked for the first time with Apple Health Kit and successfully saved a workout in Health with the basic informations (activityType, start and end).
My app is in basic function an interval timer where you can create your own workout. Now in the next step I want to add the calories burned in the workout. This information is stored in the attribute 'totalEnergyBurned'.
Do I need to calculate this value myself or can I query this value directly if the user is wearing an Apple Watch? Or maybe the value is even automatically added to the workout if there is the corresponding record? (So far I have only tested the app in the simulator, which is why I can't answer this possibility).
My current code:
func saveToHealthKit(entryID: String){
if HKHealthStore.isHealthDataAvailable() {
let healthStore = HKHealthStore()
if(healthStore.authorizationStatus(for: HKObjectType.workoutType()) == .sharingAuthorized && healthStore.authorizationStatus(for: HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.activeEnergyBurned)!) == .sharingAuthorized){
let newWorkout = HKWorkout(activityType: HKWorkoutActivityType.highIntensityIntervalTraining, start: entry.date!, end: Date())
healthStore.save(newWorkout) { success, error in
guard success else {
// Perform proper error handling here.
return
}
// Add detail samples here.
}
}
}
}
}
Thanks :)

I am not sure I understood your case correctly, but if the user is using an Apple Watch and does a workout you can query HealthKit for an HKWorkout object, which holds a totalEnergyBurned attribute.
If you are not querying this HKWorkout object, then I believe you can query for the activeEnergyBurned quantity type using the start and end date-time of the user workout in the predicate.

Related

Apple HealthKit health records

Can I add Patients health records like lab reports etc. to apple health app using health kit in swift? So far what i understand is that you can only read the health record data but you can not write it from your own health app. So what will I have to do to be able to add data in health section in apple's health app.
I have tried to look on the apple's documentation but there is no way to add health records.
I might be misunderstanding what you want to do, but you want to add data using HealthKit right?
Here's a bit of sample code I found for step data.
let healthStore = HKHealthStore()
// Request authorization to write step count data
let stepCountType = HKQuantityType.quantityType(forIdentifier: .stepCount)!
healthStore.requestAuthorization(toShare: [stepCountType]) { (success, error) in
if success {
// Create a new HKQuantitySample with the step count data
let quantity = HKQuantity(unit: HKUnit.count(), doubleValue: 1000)
let sample = HKQuantitySample(type: stepCountType, quantity: quantity, start: Date(), end: Date())
// Save the new HKQuantitySample to the Health app
healthStore.save(sample) { (success, error) in
if success {
print("Step count saved to Health app.")
} else {
print("Error saving step count to Health app: \(error!.localizedDescription)")
}
}
} else {
print("Error requesting authorization to write step count data: \(error!.localizedDescription)")
}
}
More docs at Apple.
The Health Records feature is read-only from a 3rd party API perspective. This data can only be added as a direct download from supported health systems. See here for more information: https://www.apple.com/healthcare/health-records/

geoFire .getLocation using Firebase and need an observe to monitor changes as they occur, Swift

I am using GeoFire in Swift and am able to .setLocation for a user and .getLocation I can retrieve their location and it all works good, i can then create an annotation and also create a poly line to a destination.
What I would now like to do is to move the user location along the polyline as the user travels.
To do this I was wondering how can I setup a Firebase.observe to let me know when the user moves and the map will auto update
The code I use for getLocation (snippet)
func fetchTradeLocationTest() {
guard let uid = tradeUser?.uid else { return }
let geoFire = GeoFire(firebaseRef: DB_REF.child("tradelocation"))
geoFire.getLocationForKey(uid) { (location, error) in
if (error != nil) {
print("DEBUG: An error occurred getting the location for \"tradeLocation\": \(error?.localizedDescription)")
} else if (location != nil) {
print("DEBUG: location = \(location)")
} else {
print("DEBUG: GeoFire does not contain a location for \"tradeLocation\"")
}
}
}
Wonder if anyone can guide me on how to set it up as an observer such that i get updated position.
Appreciate any help
GeoFire adds the ability to run geoqueries on Firebase, which means that you can find the keys that are in a certain geographic range and detect the data in it, and changes to that data.
In your specific use-case, you already know the key that you want to monitor. This mens you don't need a geoquery, but instead can use the regular observe API of the Realtime Database to monitor that specific key:

Trouble finding out if this counts as a read/many reads/will I get charged loads on database costs?

I am currently developing an iOS app with a google cloud firestore as a backend and I am using a few listeners to find out if data is updated and then pushing it to my device accordingly. I wrote this function that listens for a value if true or not and according to so will update an animation in my app. The trouble is I don't know if I wrote it properly and don't want to incur unnecessary reads from my database if I don't have to.
func dingAnimation() {
let identifier = tempDic![kBOUNDIDENTIFIER] as! String
if identifier != "" {
dingListener = reference(.attention).document(identifier).addSnapshotListener({ (snapshot, error) in
if error != nil {
SVProgressHUD.showError(withStatus: error!.localizedDescription)
return
}
guard let snapshot = snapshot else { return }
let data = snapshot.data() as! NSDictionary
for dat in data {
let currentId = FUser.currentId() as! String
let string = dat.key as! String
if string == currentId {
} else {
let value = dat.value as! Bool
self.shouldAnimate = value
self.animateImage()
}
}
})
}
}
This might help you.
From Firestore DOCS - Understand Cloud Firestore billing
https://firebase.google.com/docs/firestore/pricing
Listening to query results
Cloud Firestore allows you to listen to the results of a query and get realtime updates when the query results change.
When you listen to the results of a query, you are charged for a read each time a document in the result set is added or updated. You are also charged for a read when a document is removed from the result set because the document has changed. (In contrast, when a document is deleted, you are not charged for a read.)
Also, if the listener is disconnected for more than 30 minutes (for example, if the user goes offline), you will be charged for reads as if you had issued a brand-new query.

Swift 3 Completion Handler on Google Places Lookup. Due to delay how do I know when Im "done"?

Sorry, newbie here and Ive read extensively about completion handlers, dispatch queues and groups but I just can't get my head around this.
My app loads an array of Google Place IDs and then wants to query Google to get full details on each place. The problem is, due to async processing the Google Lookup Place returns immediately and the callback happens much further down the line so whats the "proper way" to know when the last bit of data has come in for my inquiries because the function ends almost immedately ?
Code is attached. Thanks in advance.
func testFunc() {
let googlePlaceIDs = ["ChIJ5fTXDP8MK4cRjIKzek6L6NM", "ChIJ9Wd6mGYGK4cRiWd0_bkohHg", "ChIJaeXT08ASK4cRkCGpGgzYpu8", "ChIJkRkS4BapK4cRXCT8-SJxNDI", "ChIJ3wDV_2zX5IkRtd0hg2i1LhE", "ChIJb4wUsI5w44kRnERe7ywQaJA"]
let placesClient = GMSPlacesClient()
for placeID in googlePlaceIDs {
placesClient.lookUpPlaceID(placeID, callback: { (place, error) in
if let error = error {
print("lookup place id query error: \(error.localizedDescription)")
return
}
guard let place = place else {
print("No place details for \(placeID)")
return
}
print("Place Name = \(place.name)")
})
}
print("Done")
}

Firebase Swift .exist() not working

Hello I am using firebase on swift and having an issue with .exist()
I am trying to do a query and check for a value, if its there I do nothing, if it isn't I add it to the list. I am just trying to avoid duplicating data this way. Heres the code:
InfoCenter.ref.child("users/\(InfoCenter.userId)/following").queryOrderedByValue()
.queryEqualToValue(firstTextField.text)
.observeEventType(.Value, withBlock: { snapshot in
if snapshot.exists(){
self.displayAlert("You already follow that person!", Title: "Whoops")
print(snapshot.value!)
} else {
InfoCenter.ref.child("users/\(InfoCenter.userId)/following").childByAutoId().setValue(TheId)
InfoCenter.ref.child("users/\(TheId)/followers").childByAutoId().setValue(InfoCenter.userId)
print(snapshot.value!)
}
})
so to me everything looks right, but when it runs snapshot.exist() always returns false but when I print snapshot.value! I get null with arrows around it (I couldn't type the arrows because SO thought it was a tag then) . So I'm confused.. how is null considered exists? Can someone please show me what to change to fix this? Thanks!!
Edit:
To be clear following is a list of users. So with in following are autoId's that have links to other users. The whole purpose of the above query is to go through the autoId's and make sure that this person does not already follow that person. Here is a snapshot of the data structure I am trying to explain:
Can I suggest an alternative? This solution reads the value as the location in question. Big benefit here is that there's no query overhead.
Assume we want to see if we follow frank and if not, follow him.
let ref = InfoCenter.ref.child("users/\(InfoCenter.userId)/following")
ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
if let person = snapshot.value as? String {
if person == "frank" {
print("you are following frank: creeeeepy")
} else {
print("you are not following frank, follow him")
}
} else {
print("node doesnt exist")
}
})
this will directly read the value at
users/some_user_id/following: "the value that's read (frank in this case)"
Edit: based on an updated question, the 'following' node should look like
users
your_uid
following
some_user_you_are_following_uid: true
another_user_you_are_following_uid: true
then you are simply checking to see if the path exists
let ref = InfoCenter.ref.child("users/\(InfoCenter.userId)/following")
let theUserRef = ref.child("some_user_you_are_following_uid")
theUserRef.observeSingleEventOfType(.Value, withBlock: { snapshot in
I think your query might not be be working user InfoCenter.userId might be an optional force unwrap and see if that return the snapshot.