尝试启动HKLiveWorkout时会意外发现nil

时间:2018-11-06 11:44:49

标签: swift health-kit hkhealthstore watch-os-5

我正在尝试制作一个健身应用程序,其中在Apple Watch上显示用户的心律。我一直在关注Apple的WWDC“锻炼的新方法”视频。这是链接https://developer.apple.com/videos/play/wwdc2018/707/?time=615

无论如何,每次我尝试运行该应用程序时,都会不断出现错误“线程1:致命错误,在展开可选值时意外发现了nil”

 session = try HKWorkoutSession(healthStore: healthStore, configuration: configuration)

我已经尝试在“尝试”之后添加一个问号(?),但所有这样做都是为了防止应用程序崩溃并且无法开始锻炼。这是完整的代码。附言我对Swift相当陌生,我发现令人难以置信的是,新的HealthKit还没有太多示例代码。 (我知道它相当新,但仍然令人沮丧:D)。感谢您的帮助

class InterfaceController: WKInterfaceController, HKWorkoutSessionDelegate, HKLiveWorkoutBuilderDelegate {

    let healthStore = HKHealthStore()
    var configuration: HKWorkoutConfiguration!

    var session: HKWorkoutSession!
    var builder: HKLiveWorkoutBuilder!


func startWorkoutWithHealthStore(){

      //  configuration.activityType = .crossTraining
    //    configuration.locationType = .indoor

        do {
            session = try? HKWorkoutSession(healthStore: healthStore, configuration: configuration)
        } catch {
            // let the user know about the error
            return
        }

        builder = session.associatedWorkoutBuilder()


        //Setup session and builder

        session.delegate = self
        builder.delegate = self

        builder.dataSource = HKLiveWorkoutDataSource(healthStore: healthStore, workoutConfiguration: configuration)


                //Start Session & Builder

        session.startActivity(with: Date())


        builder.beginCollection(withStart: Date()) { (success, error) in
            self.setDurationTimerDate() //Start the elapsed time timer
        }

    }

    @IBAction func startButtonClicked() {

        print("Start BTN clicked")
        startWorkoutWithHealthStore()

    }

    //Track Elapsed Time
    func workoutBuilderDidCollectEvent(_ workoutBuilder: HKLiveWorkoutBuilder){

        print("Collection Started")
        setDurationTimerDate()

    }

    func setDurationTimerDate(){
        print(", duration timer started"
        )
        //Create WKInterfaceTimer Date
        let timerDate = Date(timeInterval: -self.builder.elapsedTime, since: Date())
        DispatchQueue.main.async {
            self.timer.setDate(timerDate)
        }
        //Start or stop timer
        let sessionState = self.session.state
        DispatchQueue.main.async {
            sessionState == .running ? self.timer.start() : self.timer.stop()
        }
    }

    // MARK: HKLiveWorkoutBuilderDelegate
    func workoutBuilder(_ workoutBuilder: HKLiveWorkoutBuilder, didCollectDataOf collectedTypes: Set<HKSampleType>){

        for type in collectedTypes{

            guard let quantityType = type as? HKQuantityType else {
                return // Do nothing
            }


            let statistics = workoutBuilder.statistics(for: quantityType)
            //let label = labelForQuantityType(quantityType)

           // updateLabel(wkLabel, withStatistics: statistics)

            print(statistics as Any)
        }


    }

    // MARK: State Control
    func stopWorkout(){

        session.end()
        builder.endCollection(withEnd: Date()) { (success, error) in

            self.builder.finishWorkout(completion: { (workout, error) in
                self.dismiss()
            })

        }
    }


}

1 个答案:

答案 0 :(得分:1)

您不应使用Optional引发的try?将错误掩盖到HKWorkoutSession(healthStore: healthStore, configuration: configuration)中,尤其是如果您已经将语句放在do-catch块中的情况下。之所以会崩溃,是因为session被定义为一个隐式解包的可选(类型之后的!标记),它不是应该的。

如果session可能具有nil值,则应将其定义为普通可选,并在每次访问它时安全地解开/可选链。

class InterfaceController: WKInterfaceController, HKWorkoutSessionDelegate, HKLiveWorkoutBuilderDelegate {

    let healthStore = HKHealthStore()
    let configuration = HKWorkoutConfiguration()

    var session: HKWorkoutSession? = nil
    var builder: HKLiveWorkoutBuilder? = nil


    func startWorkoutWithHealthStore(){
        configuration.activityType = .crossTraining
        configuration.locationType = .indoor

        do {
            session = try HKWorkoutSession(healthStore: healthStore, configuration: configuration)
        } catch {
            print(error)
            session = nil
            return
        }

        builder = session?.associatedWorkoutBuilder()


        //Setup session and builder

        session?.delegate = self
        builder?.delegate = self

        builder?.dataSource = HKLiveWorkoutDataSource(healthStore: healthStore, workoutConfiguration: configuration)


        //Start Session & Builder
        session?.startActivity(with: Date())


        builder?.beginCollection(withStart: Date()) { (success, error) in
            self.setDurationTimerDate() //Start the elapsed time timer
        }

    }
...
}