我正在尝试制作一个健身应用程序,其中在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()
})
}
}
}
答案 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
}
}
...
}