WWDC Quick Look 💓 By SwiftGGTeam
Build a research and care app, part 2: Schedule tasks

Build a research and care app, part 2: Schedule tasks

元の動画を見る

ハイライト

ResearchKit は CareKit とリンクされているため、開発者は数行のコード内でアンケートの作成、データ収集、進捗状況の追跡を完了でき、患者が紙のアンケートに記入するためにクリニックに行く必要がなくなります。

主な内容

紙のアンケートからデジタルフォローアップへ

臨床研究や患者の追跡調査を行う場合、最大の悩みはデータ収集です。研究者はアンケートを作成し、印刷して配布し、収集し、整理する必要がありますが、患者はアンケートに記入するために診療所で列に並ばなければなりません。プロセス全体は非効率的で、エラーが発生しやすくなります。

Apple が提供するソリューションは、ResearchKit と CareKit を組み合わせたものです。ResearchKit は専門的なアンケートとアクティブなタスク (関節の可動性の測定など) をレンダリングする役割を果たし、CareKit はタスクのスケジュールを管理し、データを保持する役割を担います。この 2 つは単純な変換メカニズムを通じて接続されます。

複数の質問フォーム: 複数の評価を一度に完了します

01:46

ジェイミーの理学療法アプリは、痛みのレベルと睡眠時間という 2 つのデータを毎日収集します。リサーチキットORKFormStepユーザーの手順を減らすために、複数の質問を同じページに配置できます。

質問ごとに 1 つを使用しますORKFormItem定義、経由ORKScaleAnswerFormatスライダーとしてレンダリングされます。痛みのスコアは 1 ~ 10 の範囲で、睡眠時間は 0 ~ 12 時間の範囲でした。スライダーは、紙のアンケートの塗りつぶし丸印よりも直感的で、ユーザーに受け入れられやすいです。

データ フロー: アンケートの回答から CareKit の結果まで

04:12

ResearchKit がアンケートに回答すると、ORKTaskResult、これは入れ子構造です。ルート ノードはタスクの結果であり、サブノードは各フォーム ステップに対応し、さらにその下には各質問に対する回答があります。

開発者は、ネストされた結果から特定の値を抽出し、それらをパッケージ化する変換関数を作成する必要があります。OCKOutcomeValue、CareKit のローカル データベースに保存されます。正常に保存されると、CareKit はインターフェイス上の完了リングとタスク カードのステータスを自動的に更新します。

動的スケジュール: 時間の経過とともに減少するリハビリテーションタスク

10:01

通常、リハビリテーションセッションの頻度は時間の経過とともに減少します。ジェイミーのリクエストは、可動域の測定を最初の 1 週間は毎日、その後は週に 1 回、そして 1 か月後には完全に中止することです。

ケアキット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複数の質問を 1 つのページに結合して、ユーザーの手順を削減します

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:)レイヤーごとに検索します
  • OCKOutcomeValuekindこの属性は、後でデータをタイプ別に取得するために使用され、常に設定することをお勧めします。
  • 各質問の結果は、対応する質問と一致する必要があります。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.kneeRangeOfMotionTaskResearchKit で事前定義された医療測定タスクです
  • limbOption: .left左足の寸法を指定し、excludeConclusionデフォルトの完了プロンプトを削除する
  • カスタム ステップを追加して、プロンプトを特定のアプリケーション シナリオにより適したものにすることができます。

重要ポイント

  1. やるべきこと: 紙の日記に代わる慢性疾患患者向けの在宅フォローアップ アプリを作成する 実行する価値がある理由: ResearchKit のフォームとアクティブなタスクはデータ収集を標準化し、CareKit のカレンダー システムはフォローアップ計画を自動化します。 開始方法:からORKFormStep毎日のアンケートを設計することから始めて、OCKScheduleリマインダーの頻度を管理する

  2. やるべきこと: 健康アプリに関節可動性または歩行分析機能を追加する 実行する価値がある理由: ResearchKit にはさまざまな医療測定タスクが組み込まれているため、開発者自身がセンサー アルゴリズムを実装する必要がありません。 開始方法: 電話ORKOrderedTask.kneeRangeOfMotionTaskまたはORKOrderedTask.walkingTask、合格ORKTaskResult測定データの抽出

  3. 内容: 頻度の漸減をサポートするリハビリテーション トレーニング プログラムを構築する 価値がある理由: CareKit の複合スケジュールは、複数のスケジュールで使用できます。OCKScheduleElement複雑なタイミングルールをつなぎ合わせます 開始方法: 複数のスケジュール要素を定義し、異なるスケジュール要素を設定しますstartendそしてinterval、使用OCKSchedule.composingマージ

  4. やるべきこと: ResearchKit アンケート データを HealthKit に接続する 実行する価値がある理由: 痛みのスコア、睡眠の質、その他のデータを HealthKit に書き込むことで、他の健康データと合わせて全体像を形成できます。 開始方法:extractCheckInOutcomesHealthKit 書き込みロジックを追加し、使用しますHKQuantityType値を保存する

関連セッション

コメント

GitHub Issues · utterances