0

注意:我在两天前尝试在苹果开发者论坛上发帖,也没有收到任何回复

我一直坚持我的项目的这一部分,因为我想反映苹果为向用户显示任务而设置护理视图的方式。由于某种原因,我无法将“OCKSurveyTaskViewController”子类化,因为我得到的错误是:

“在范围内找不到类型‘OCKSurveyTaskViewController’”

我已经通过 SPM 2 或 3 次重新安装了 CareKit,即使我看到确切的 OCKSurveyTaskViewController.swift 文件并且它在代码中列为 CareKit/iOS 中的一个开放类,我也无法弄清楚为什么我不能对它进行子类化Xcode 中的 /Task/ViewController 目录。

谁能给我一些指导或另一种方式来以另一种方式显示我每天为用户建立的 ORKTasks?我更喜欢苹果在他们的 wwdc21 CareKit 代码中使用的方法,但可惜我已经坚持了太久,这是我下一步所必需的。

这是我的文件代码:

import UIKit
import CareKit
import CareKitUI
import CareKitStore
import ResearchKit
import os.log

class StudyTaskFeedViewController: OCKDailyTasksPageViewController, OCKSurveyTaskViewController {}

这是 OCKSurveyTaskViewController.swift 文件的代码:

#if !os(watchOS) && canImport(ResearchKit)

import CareKitStore
import CareKitUI
import ResearchKit
import UIKit

// MARK: OCKSurveyTaskViewControllerDelegate

public protocol OCKSurveyTaskViewControllerDelegate: AnyObject {

    func surveyTask(
        viewController: OCKSurveyTaskViewController,
        for task: OCKAnyTask,
        didFinish result: Result<ORKTaskViewControllerFinishReason, Error>)

    func surveyTask(
        viewController: OCKSurveyTaskViewController,
        shouldAllowDeletingOutcomeForEvent event: OCKAnyEvent) -> Bool
}

public extension OCKSurveyTaskViewControllerDelegate {

    func surveyTask(
        viewController: OCKSurveyTaskViewController,
        for task: OCKAnyTask,
        didFinish result: Result<ORKTaskViewControllerFinishReason, Error>) {
        // No-op
    }

    func surveyTask(
        viewController: OCKSurveyTaskViewController,
        shouldAllowDeletingOutcomeForEvent event: OCKAnyEvent) -> Bool {
        return true
    }
}

open class OCKSurveyTaskViewController: OCKTaskViewController<OCKTaskController, OCKSurveyTaskViewSynchronizer>, ORKTaskViewControllerDelegate {

    private let extractOutcome: (ORKTaskResult) -> [OCKOutcomeValue]?

    public let survey: ORKTask

    public weak var surveyDelegate: OCKSurveyTaskViewControllerDelegate?

    public convenience init(
        task: OCKAnyTask,
        eventQuery: OCKEventQuery,
        storeManager: OCKSynchronizedStoreManager,
        survey: ORKTask,
        viewSynchronizer: OCKSurveyTaskViewSynchronizer = OCKSurveyTaskViewSynchronizer(),
        extractOutcome: @escaping (ORKTaskResult) -> [OCKOutcomeValue]?) {

        self.init(
            taskID: task.id,
            eventQuery: eventQuery,
            storeManager: storeManager,
            survey: survey,
            viewSynchronizer: viewSynchronizer,
            extractOutcome: extractOutcome
        )
    }

    public init(
        taskID: String,
        eventQuery: OCKEventQuery,
        storeManager: OCKSynchronizedStoreManager,
        survey: ORKTask,
        viewSynchronizer: OCKSurveyTaskViewSynchronizer = OCKSurveyTaskViewSynchronizer(),
        extractOutcome: @escaping (ORKTaskResult) -> [OCKOutcomeValue]?) {

        self.survey = survey
        self.extractOutcome = extractOutcome

        super.init(
            viewSynchronizer: viewSynchronizer,
            taskID: taskID,
            eventQuery: eventQuery,
            storeManager: storeManager
        )
    }

    override open func taskView(
        _ taskView: UIView & OCKTaskDisplayable,
        didCompleteEvent isComplete: Bool,
        at indexPath: IndexPath,
        sender: Any?) {

        guard isComplete else {

            if let event = controller.eventFor(indexPath: indexPath),

               let delegate = surveyDelegate,

               delegate.surveyTask(
                    viewController: self,
                    shouldAllowDeletingOutcomeForEvent: event) == false {

                return
            }

            let cancelAction = UIAlertAction(
                title: "Cancel",
                style: .cancel,
                handler: nil
            )

            let confirmAction = UIAlertAction(
                title: "Delete", style: .destructive) { _ in
                
                super.taskView(
                    taskView,
                    didCompleteEvent: isComplete,
                    at: indexPath,
                    sender: sender
                )
            }

            let warningAlert = UIAlertController(
                title: "Delete",
                message: "Are you sure you want to delete your response?",
                preferredStyle: .actionSheet
            )

            warningAlert.addAction(cancelAction)
            warningAlert.addAction(confirmAction)
            present(warningAlert, animated: true, completion: nil)

            return
        }

        let surveyViewController = ORKTaskViewController(
            task: survey,
            taskRun: nil
        )

        let directory = FileManager.default.urls(
            for: .documentDirectory,
            in: .userDomainMask
        ).last!.appendingPathComponent("ResearchKit", isDirectory: true)

        surveyViewController.outputDirectory = directory
        surveyViewController.delegate = self

        present(surveyViewController, animated: true, completion: nil)
    }

    // MARK: ORKTaskViewControllerDelegate
    
    open func taskViewController(
        _ taskViewController: ORKTaskViewController,
        didFinishWith reason: ORKTaskViewControllerFinishReason,
        error: Error?) {

        taskViewController.dismiss(animated: true, completion: nil)

        guard let task = controller.taskEvents.first?.first?.task else {
            assertionFailure("Task controller is missing its task")
            return
        }

        if let error = error {
            surveyDelegate?.surveyTask(
                viewController: self,
                for: task,
                didFinish: .failure(error)
            )
            return
        }

        guard reason == .completed else {
            return
        }

        let indexPath = IndexPath(item: 0, section: 0)

        guard let event = controller.eventFor(indexPath: indexPath) else {
            return
        }

        guard let values = extractOutcome(taskViewController.result) else {
            return
        }

        let outcome = OCKOutcome(
            taskUUID: event.task.uuid,
            taskOccurrenceIndex: event.scheduleEvent.occurrence,
            values: values
        )

        controller.storeManager.store.addAnyOutcome(
            outcome,
            callbackQueue: .main) { result in

            if case let .failure(error) = result {

                self.surveyDelegate?.surveyTask(
                    viewController: self,
                    for: task,
                    didFinish: .failure(error)
                )
            }

            self.surveyDelegate?.surveyTask(
                viewController: self,
                for: task,
                didFinish: .success(reason)
            )
        }
    }
}

#endif
4

1 回答 1

0

当我尝试在我自己的应用程序中从“恢复”应用程序中重现演示代码时,我遇到了同样的问题。在将我的项目设置与“恢复”进行比较后,我注意到我错过了在目标应用的 Sign&Capabilities 中添加“HealthKit”的功能。添加此功能后,它起作用了。

于 2021-12-01T06:28:26.387 回答