Part 3, Episode 13, Extract OCKOutcomeValue from ORKTaskResult
In this episode, I want to show you how to store the ORKTaskResult by creating OCKOutcomeValue.
As I mentioned earlier the schema of CareKitStore, out of each task, you have an outcome, but if you are using ResearchKit to have a survey, you have to save the outcome of the ResearchKit survey manually to the CareKitStore because there is no storage or anything available for ResearchKit to save the data.
Let’s jump to Xcode, open the SurveyViewModel from Project Navigator, and create the first function to extract checkInSurveyOutcome.
static func checkInSurveyOutcome(_ result: ORKTaskResult) -> [OCKOutcomeValue]? {
guard
let response = result.results?
.compactMap({ $0 as? ORKStepResult })
.first(where: { $0.identifier == IdentifierModel.checkinForm.rawValue }),
let scaleResults = response.results?
.compactMap({ $0 as? ORKScaleQuestionResult }),
let musclePainAnswer = scaleResults
.first(where: { $0.identifier == IdentifierModel.checkinMuscle.rawValue })?
.scaleAnswer,
let headacheAnswer = scaleResults
.first(where: { $0.identifier == IdentifierModel.checkinHeadache.rawValue })?
.scaleAnswer,
let tirednessAnswer = scaleResults
.first(where: { $0.identifier == IdentifierModel.checkinTiredness.rawValue })?
.scaleAnswer,
let feverAnswer = scaleResults
.first(where: { $0.identifier == IdentifierModel.checkinFever.rawValue })?
.scaleAnswer,
let nauseaAnswer = scaleResults
.first(where: { $0.identifier == IdentifierModel.checkinNausea.rawValue })?
.scaleAnswer
else {
assertionFailure("Failed to extract answers from check in survey!")
return nil
}
var musclePainValue = OCKOutcomeValue(Double(truncating: musclePainAnswer))
musclePainValue.kind = IdentifierModel.checkinMuscle.rawValue
var headacheValue = OCKOutcomeValue(Double(truncating: headacheAnswer))
headacheValue.kind = IdentifierModel.checkinHeadache.rawValue
var tirednessValue = OCKOutcomeValue(Double(truncating: tirednessAnswer))
tirednessValue.kind = IdentifierModel.checkinTiredness.rawValue
var feverValue = OCKOutcomeValue(Double(truncating: feverAnswer))
feverValue.kind = IdentifierModel.checkinFever.rawValue
var nauseaValue = OCKOutcomeValue(Double(truncating: nauseaAnswer))
nauseaValue.kind = IdentifierModel.checkinNausea.rawValue
return [musclePainValue, headacheValue, tirednessValue, feverValue, nauseaValue]
}
What you did here is your search for an identifier that you’ve assigned it to the survey for each step and then extract it from the result.
Next step is to make an OCKOutcomeValue based on the data you’ve extracted from the survey and finally make an array and return it.
Now let’s navigate to TaskViewModel and put this function for the CheckIn completion handler, find the checkIn case, then replace the extractOutcome value with this:
SurveyViewModel.checkInSurveyOutcome(_:)
You just used the function you’ve made as an outcome extractor, allowing CareKitStore to store the right value with the right data type and unique identifier.
Build and run; it should work as before; however, you store the value of the checkin survey somewhere now.
Next is to do the same process for the motion check task as well. Navigate to SurveyViewModel and add a new function to extract the range of motion data.
static func rangeOfMotionSurveyOutcome(_ result: ORKTaskResult) -> [OCKOutcomeValue]? {
guard
let motionResult = result.results?
.compactMap({ $0 as? ORKStepResult })
.compactMap({ $0.results })
.flatMap({ $0 })
.compactMap({ $0 as? ORKRangeOfMotionResult })
.first else {
assertionFailure("Failed to parse range of motion result")
return nil
}
var range = OCKOutcomeValue(motionResult.range)
range.kind = #keyPath(ORKRangeOfMotionResult.range)
return [range]
}
Here you search for the ORKRangeOfMotionResult in a different way, which is a type; in some of the results, you might want to extract the data without knowing the identifier, then you can do this, especially your data is a range of something for example here is a range of motion.
Let’s use this and save the data in the CareKitStore. Navigate to TaskViewModel and then inside of motionCheck case replace the extractOutcome value with this:
SurveyViewModel.rangeOfMotionSurveyOutcome(_:)
You just used the function you’ve made as an outcome extractor, allowing CareKitStore to store the range of motion survey outcome.
Remove the app from your phone or simulator and then build and run and do all the steps to store the data in the CareKitStore in the following episodes; you’ll learn how to show those values in the overview tab.