尝试启动 HKLiveWorkout 在会话中意外发现 nil

Attempting to start HKLiveWorkout keep getting unexpectedly found nil on session

我正在尝试制作一个锻炼应用程序,让用户的心率显示在 Apple Watch 上。我一直在关注 Apple 的 WWDC "New Ways to Work with workouts" 视频。这是 link https://developer.apple.com/videos/play/wwdc2018/707/?time=615

无论如何,每次我尝试 运行 应用程序时,我都会收到错误 "Thread 1: Fatal Error unexpectedly found nil while unwrapping an optional value "

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

我尝试在 "try" 之后添加一个问号 (?),但所做的只是防止应用程序崩溃并且不会开始锻炼。这是完整的代码。 P.S。我是 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()
            })

        }
    }


}

您不应该使用 HKWorkoutSession(healthStore: healthStore, configuration: configuration) 抛出的 try? 将错误掩盖到 Optional 中,尤其是当您已经将语句放在 do-catch 块中时。你会崩溃,因为 session 被定义为一个隐式展开的可选(! 标记在类型之后),它不应该是。

如果 session 可能有一个 nil 值,并且每次访问它时安全地 unwrap/optional 链接它,您应该将其定义为普通可选值。

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
        }

    }
...
}