Highlight
ResearchKit 与 CareKit 联动,让开发者可以在几行代码内完成问卷创建、数据收集和进度追踪,患者无需再到诊所填写纸质问卷。
核心内容
从纸质问卷到数字化随访
做临床研究或患者随访时,最头疼的是数据收集。研究者需要设计问卷、打印分发、回收整理,患者则要在诊所排队填写。整个过程低效且容易出错。
Apple 给出的方案是 ResearchKit + CareKit 的组合。ResearchKit 负责呈现专业的调查问卷和主动任务(如测量关节活动度),CareKit 负责管理任务日程和持久化数据。两者通过一套简单的转换机制衔接。
多问题表单:一次完成多项评估
(01:46)
Jamie 的物理治疗 App 需要每天收集两项数据:疼痛程度和睡眠时长。ResearchKit 的 ORKFormStep 可以把多个问题放在同一页,减少用户的操作步骤。
每个问题用一个 ORKFormItem 定义,通过 ORKScaleAnswerFormat 呈现为滑块。疼痛评分范围 1-10,睡眠时长范围 0-12 小时。滑块比纸质问卷的填涂圆圈更直观,用户也更容易接受。
数据流转:从问卷答案到 CareKit 结果
(04:12)
ResearchKit 完成问卷后会返回一个 ORKTaskResult,这是一个嵌套结构。根节点是任务结果,子节点对应每个表单步骤,再往下是每个问题的答案。
开发者需要编写一个转换函数,从嵌套结果中提取具体数值,包装成 OCKOutcomeValue,存入 CareKit 的本地数据库。一旦保存成功,CareKit 会自动更新界面上的完成环和任务卡片状态。
动态日程:随时间递减的康复任务
(10:01)
康复训练的频率通常会随时间降低。Jamie 的需求是:关节活动度测量在第一周每天一次,之后每周一次,一个月后完全停止。
CareKit 的 OCKScheduleElement 支持这种复合日程。开发者可以定义多个日程元素,每个元素有独立的起始时间、结束时间和重复间隔,然后用 OCKSchedule.composing 将它们合并成一个完整的日程。
主动任务:在家完成医学测量
(12:00)
ResearchKit 内置了关节活动度(Range of Motion)测量任务。用户按照屏幕提示将设备放在膝盖上,完成屈伸动作,系统通过传感器自动计算活动角度。这原本需要在诊所由治疗师辅助完成,现在患者在家就能自行测量。
详细内容
创建多问题表单
import ResearchKit
func createCheckInSurvey() -> ORKTask {
// 定义疼痛问题
let painItem = ORKFormItem(
identifier: "pain",
text: "How much pain are you experiencing?",
answerFormat: ORKScaleAnswerFormat(
maximumValue: 10,
minimumValue: 1,
defaultValue: 5,
step: 1,
vertical: false,
maximumValueDescription: "Severe",
minimumValueDescription: "None"
)
)
painItem.isOptional = false
// 定义睡眠问题
let sleepItem = ORKFormItem(
identifier: "sleep",
text: "How many hours of sleep did you get?",
answerFormat: ORKScaleAnswerFormat(
maximumValue: 12,
minimumValue: 0,
defaultValue: 7,
step: 1,
vertical: false,
maximumValueDescription: "12+ hours",
minimumValueDescription: "None"
)
)
sleepItem.isOptional = false
// 创建表单步骤
let formStep = ORKFormStep(
identifier: "checkin.form",
title: "Daily Check-In",
text: "Please answer the following questions."
)
formStep.formItems = [painItem, sleepItem]
formStep.isOptional = false
// 组装为有序任务
return ORKOrderedTask(identifier: "checkin", steps: [formStep])
}
关键点:
ORKScaleAnswerFormat创建滑块输入,比文本框更适合数值型问卷isOptional = false确保问题不可跳过,保证数据完整性ORKFormStep将多个问题合并到一页,减少用户操作步骤
解析 ResearchKit 结果并转换为 CareKit 数据
import CareKit
import ResearchKit
func extractCheckInOutcomes(
task: OCKAnyTask,
result: ORKTaskResult
) -> [OCKOutcomeValue] {
// 从根结果中找到表单步骤结果
guard let formResult = result.stepResult(forStepIdentifier: "checkin.form"),
let questionResults = formResult.results as? [ORKScaleQuestionResult]
else {
return []
}
var outcomes: [OCKOutcomeValue] = []
// 提取疼痛评分
if let painResult = questionResults.first(where: { $0.identifier == "pain" }),
let painValue = painResult.scaleAnswer {
let painOutcome = OCKOutcomeValue(painValue.doubleValue)
painOutcome.kind = "pain"
outcomes.append(painOutcome)
}
// 提取睡眠时长
if let sleepResult = questionResults.first(where: { $0.identifier == "sleep" }),
let sleepValue = sleepResult.scaleAnswer {
let sleepOutcome = OCKOutcomeValue(sleepValue.doubleValue)
sleepOutcome.kind = "sleep"
outcomes.append(sleepOutcome)
}
return outcomes
}
关键点:
ORKTaskResult是嵌套结构,需要通过stepResult(forStepIdentifier:)逐层向下查找OCKOutcomeValue的kind属性用于后续按类型检索数据,建议始终设置- 每个问题结果需要匹配对应的
identifier才能正确提取
创建复合日程
import CareKit
func createRangeOfMotionSchedule() -> OCKSchedule {
let calendar = Calendar.current
let thisMorning = calendar.startOfDay(for: Date())
let nextWeek = calendar.date(byAdding: .day, value: 7, to: thisMorning)!
let nextMonth = calendar.date(byAdding: .month, value: 1, to: thisMorning)!
// 第一周:每天一次
let dailyElement = OCKScheduleElement(
start: thisMorning,
end: nextWeek,
interval: DateComponents(day: 1),
text: "Daily measurement",
targetValues: [],
duration: .allDay
)
// 第二周到月底:每周一次
let weeklyElement = OCKScheduleElement(
start: nextWeek,
end: nextMonth,
interval: DateComponents(day: 7),
text: "Weekly measurement",
targetValues: [],
duration: .allDay
)
// 合并两个日程元素
return OCKSchedule.composing([dailyElement, weeklyElement])
}
关键点:
OCKScheduleElement定义一个时间区间内的重复规则interval使用DateComponents,支持天、周、月等多种粒度OCKSchedule.composing将多个元素合并,元素之间的时间区间互不重叠- 超过
end日期后任务自动消失,无需手动清理
使用 ResearchKit 内置的关节活动度任务
import ResearchKit
func createRangeOfMotionTask() -> ORKTask {
var predefinedTask = ORKOrderedTask.kneeRangeOfMotionTask(
withIdentifier: "rom.left.knee",
limbOption: .left,
intendedUseDescription: nil,
options: [.excludeConclusion]
)
// 添加自定义完成提示
let completionStep = ORKCompletionStep(identifier: "completion")
completionStep.title = "Great job!"
completionStep.text = "Keep up the good work with your physical therapy."
predefinedTask.appendSteps([completionStep])
return predefinedTask
}
关键点:
ORKOrderedTask.kneeRangeOfMotionTask是 ResearchKit 预定义的医学测量任务limbOption: .left指定测量左腿,excludeConclusion移除默认的完成提示- 可以追加自定义步骤,让提示语更贴合具体应用场景
核心启发
-
做什么:为慢性病患者打造一款居家随访 App,替代纸质日记本 为什么值得做:ResearchKit 的表单和主动任务让数据收集标准化,CareKit 的日程系统让随访计划自动化 怎么开始:从
ORKFormStep设计每日问卷入手,用OCKSchedule管理提醒频率 -
做什么:在健康类 App 中加入关节活动度或步态分析功能 为什么值得做:ResearchKit 内置了多种医学测量任务,开发者无需自己实现传感器算法 怎么开始:调用
ORKOrderedTask.kneeRangeOfMotionTask或ORKOrderedTask.walkingTask,通过ORKTaskResult提取测量数据 -
做什么:构建一个支持递减频率的康复训练计划 为什么值得做:CareKit 的复合日程可以用多个
OCKScheduleElement拼接出任意复杂的时序规则 怎么开始:定义多个日程元素,分别设置不同的start、end和interval,用OCKSchedule.composing合并 -
做什么:将 ResearchKit 问卷数据与 HealthKit 打通 为什么值得做:疼痛评分、睡眠质量等数据可以写入 HealthKit,与其他健康数据形成完整画像 怎么开始:在
extractCheckInOutcomes中增加 HealthKit 写入逻辑,使用HKQuantityType保存数值
关联 Session
- Build a research and care app, part 1: Getting started — Code-along 系列第一部分,搭建 onboarding 和 consent 流程
- Build a research and care app, part 3: Visualize progress — Code-along 系列第三部分,用 CareKit 可视化康复进度
- What’s new in HealthKit — HealthKit 新特性,与 CareKit 数据互通
评论
GitHub Issues · utterances