The end and the beginning of the year for developers, as a rule, are always filled with a large number of projects. Having dealt with urgent matters and rolled up our sleeves, we at Techmas promised to share even more of our developments with colleagues.
Despite the growing popularity of applications that HealthKit is already using, the demand for mobile health assessment solutions continues
to grow .
To clarify all the basic principles of working with the platform, we decided to return to the example from the last publication and supplement it with work with data samples from Health.
Introduction
Recall that earlier we made an overview of the overall functionality of HealthKit, reviewed the application for authentication in Health and the output characteristics of the user. Now we will deal with samples (
samples ) for reading and writing new training data.
')
Samples (
samples ) differ from characteristics (
characteristics ) in that they change over time and depend on user behavior. For example, samples are used to add new training data, visualize them, define and calculate additional parameters.
In the example, we show how to read data on the height and weight of the user from the Health application. Next, we calculate the BMI (Body Mass Index) indicator and add the resulting value to track the dynamics of its change.
So back to the application from the previous section. His code is
here .
Sample preparation
Create test data for the sample into the Health application.
To do this, select the Weight item on the Body Measurements tab and enter several key points with information about the weight (weight) via Add Data Point.
Data can be entered in any number and number at different intervals.
Now we get permission to work with the parameters of the sample. Add
authorizeHealthKit () to the authorization function (separately we talked about authorization earlier):
let healthKitTypesToWrite = Set(arrayLiteral: HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass)!, HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierActiveEnergyBurned)!, HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning)! )
Reading a sample from Health
In our example, we will create the
readMostRecentSample () function, which will read the indicators by date and type.
To obtain a sample, you must use a subclass of
HKSampleQuery , which is inherited from
HKQuery . In essence, it works similar to Core Data's
NSFetchedRequest .
When forming the request, the following parameters are available:
1. Sample type (for example, weight or height),
Type .
2. Conditions for the selection of the sample (period, values, etc.),
NSPredicate .
3. Sort method,
NSSortDescriptors .
The second and third parameters are optional. After forming the query,
executeQuery () must be executed to display its result.
In our example, we will create a method to get the last value for the specified sample type. Add the following code to the
readMostRecentSample () function:
// 1. let past = NSDate.distantPast() let now = NSDate() let mostRecentPredicate = HKQuery.predicateForSamplesWithStartDate(past, endDate:now, options: .None) // 2. let sortDescriptor = NSSortDescriptor(key:HKSampleSortIdentifierStartDate, ascending: false) // 3. let limit = 1 // 4. let sampleQuery = HKSampleQuery(sampleType: sampleType, predicate: mostRecentPredicate, limit: limit, sortDescriptors: [sortDescriptor]) { (sampleQuery, results, error ) -> Void in if let queryError = error { completion(nil,error) return; } // let mostRecentSample = results!.first as? HKQuantitySample if completion != nil { completion(mostRecentSample,nil) } } // 5. self.healthKitStore.executeQuery(sampleQuery)
Our function allows you to get the latest data on samples of a particular type. For simplicity, the
readMostRecentSample () call
will be added to the
viewDidLoad () method:
// 1. HKSampleType let sampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass) // 2. self.readMostRecentSample(sampleType!, completion: { (mostRecentWeight, error) -> Void in if( error != nil ) { print("Error reading weight from HealthKit Store: \(error.localizedDescription)") return; }
Here we use
quantityTypeForIdentifier to determine the required sample, in our case
HKQuantityTypeIdentifierBodyMass .
BMI value calculation
Now we will create a set for calculating and recording BMI. It will be calculated by the formula:
bmi = weight / height ^ 2
As shown above, select the weight value (weight) from Health. In the same way, we will get the height (height) of the user (replacing the data type and format, we use
HKQuantityTypeIdentifierHeight) .
Here we need the
HKQuantitySample object. You must also specify:
•
HKQuantityType object
type to save. In our case, this is
HKQuantityTypeIdentifierBodyMassIndex .
•
HKQuantity object. It is initialized with the passed value from the bmi parameter. It is important that
HKUnit.countUnit () is used to convert the Double scalar type, which allows you to convert types to the necessary units.
Then the BMI calculation will be as follows:
var weight: HKQuantitySample var weightLocalizedString = “empty" weight = (mostRecentWeight as? HKQuantitySample)!; kilograms = weight.quantity.doubleValueForUnit(HKUnit.gramUnitWithMetricPrefix(.Kilo)) let weightFormatter = NSMassFormatter() weightFormatter.forPersonMassUse = true; weightLocalizedString = weightFormatter.stringFromKilograms(kilograms) print(weightLocalizedString) let weightInKilograms = kilograms let heightInMeters: Double = 180 let bmi = weightInKilograms / heightInMeters * heightInMeters print(String(format: "%.02f", bmi))
Also note the use of formatting results using
NSMassFormatter .
NSMassFormater itself, in essence, is not part of HelathKit, but it allows you to work with Health data types. In particular, if kilograms are used in the application, and the device does not use the metric system, we are able to bring the units of measurement to the desired form.
We will not dwell on issues of the interface, so the results will display in the console.
Adding a new sample to Health
Finally, to write the resulting BMI value to HelathKit, create a
saveBMISample method
(bmi: Double, date: NSDate) . Output parameters: the BMI value itself and the date of its registration.
// 1. BMI let bmiType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMassIndex) let bmiQuantity = HKQuantity(unit: HKUnit.countUnit(), doubleValue: bmi) let bmiSample = HKQuantitySample(type: bmiType, quantity: bmiQuantity, startDate: date, endDate: date) // 2. Health healthKitStore.saveObject(bmiSample, withCompletion: { (success, error) -> Void in if( error != nil ) { println("Error saving BMI sample: \(error.localizedDescription)") } else { println("BMI sample saved successfully!") } })
The new BMI value is available for both standard viewing and can be used by a third-party authorized application.
Note
In practice, it makes sense to put all methods for working with HealthKit into a separate class.
For our example, we limited ourselves to a demonstration of the key stages of working with the platform.
The code for the final application is
here .