底部更新时间:美国东部标准时间01/30/16 @ 7:40 PM
因此,我试图运行StatisticsQuery以将当天的总计DistanceRunningWalking
存储在HealthKit中,然后将该查询的结果存储在变量中,以供日后使用。该查询似乎运行良好,因为我已经测试过将查询结果(totalDistance
)从函数内打印到Label。我遇到的问题是尝试将结果保存到变量时。
这是我的HealthKitManager.swift文件中的代码:
import HealthKit
class HealthKitManager {
class var sharedInstance: HealthKitManager {
struct Singleton {
static let instance = HealthKitManager()
}
return Singleton.instance
}
let healthStore: HKHealthStore? = {
if HKHealthStore.isHealthDataAvailable() {
return HKHealthStore()
} else {
return nil
}
}()
let distanceCount = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning)
let distanceUnit = HKUnit(fromString: "mi")
}
ViewController顶部的代码:(这是我要保存到的变量)
let healthKitManager = HealthKitManager.sharedInstance
//Set up variable to contain result of query
var distanceTotalLength:Double?
viewDidLoad
中的代码://Run the function
requestHealthKitAuthorization()
//Set value of variable to query result
distanceTotalLength = queryDistanceSum()
ViewController主体中的代码:
func requestHealthKitAuthorization() {
let dataTypesToRead = NSSet(objects: healthKitManager.distanceCount!)
healthKitManager.healthStore?.requestAuthorizationToShareTypes(nil, readTypes: dataTypesToRead as NSSet as? Set<HKObjectType>, completion: { [unowned self] (success, error) in
if success {
self.queryDistanceSum()
} else {
print(error!.description)
}
})
}
func queryDistanceSum() {
let sumOption = HKStatisticsOptions.CumulativeSum
let startDate = NSDate().dateByRemovingTime()
let endDate = NSDate()
let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: endDate, options: [])
let statisticsSumQuery = HKStatisticsQuery(quantityType: healthKitManager.distanceCount!, quantitySamplePredicate: predicate, options: sumOption) {
[unowned self] (query, result, error) in
if let sumQuantity = result?.sumQuantity() {
dispatch_async(dispatch_get_main_queue(), {
let totalDistance = sumQuantity.doubleValueForUnit(self.healthKitManager.distanceUnit)
self.distanceTotalLength = totalDistance
})
}
}
healthKitManager.healthStore?.executeQuery(statisticsSumQuery)
}
在最后一行
return (distanceTotalLength)!
上,启动读取fatal error: unexpectedly found nil while unwrapping an Optional value
的应用程序时出现错误。我已经意识到这很可能是一个范围问题(尽管我可能做错了其他事情,所以请指出任何事情),但是我无法自己查看/找到解决问题的方法。任何帮助,将不胜感激,所以在此先感谢!
更新:美国东部标准时间〜7:40PM @ 01/30/16
好的,所以我一直在尝试自己解决此问题,并发现了一个问题:代码肯定可以正常工作。通过在ViewController顶部为
0
分配distanceTotalLength
的初始值,我能够运行应用程序而不会出现致命错误。但是,当我随后尝试通过prepareForSegue函数将distanceTotalLength
的值传递到另一个视图时,我意识到毕竟是在分配它。当我转到该视图时,它不是使用0
的初始值,而是查询的结果。我进行测试的方法是在变量
var distanceTotalLength:Double = 0
之前的viewController顶部设置变量viewDidLoad
,然后在viewDidLoad
内使用distanceLabel.text = String(distanceTotalLength)
将值分配给标签,正如我所说,标签最终显示为0
。但是,当我过渡到另一个视图时,传递distanceTotalLength
的值并在那里打印该值,它就可以工作。在第二个屏幕上,它打印查询结果,而不是0
。因此,我假设问题是查询运行,然后在视图已加载之后为其分配所有预定义值。不幸的是,这是我再次陷入困境的地方。我已经走了这么远,现在有人知道如何帮助我吗?
最佳答案
你是对的。在您的HKStatisticsQuery
完成执行之后被调用的完成处理程序关闭发生在稍后的时间。可以将查询执行视为在邮件中向某人发送一封信,然后等待他们的回复;它不会立即发生,但与此同时您可以离开并做其他事情。
要在您的代码中处理此问题,请向queryDistanceSum方法添加您自己的完成闭包。然后在设置self.distanceTotalLength = totalDistance
之后,调用该闭包。在实现闭包的代码时,请添加设置距离后需要完成的所有操作,例如更新UI。
func queryDistanceSum(completion: () -> Void) { // <----- add the closure here
let sumOption = HKStatisticsOptions.CumulativeSum
let startDate = NSDate().dateByRemovingTime()
let endDate = NSDate()
let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: endDate, options: [])
let statisticsSumQuery = HKStatisticsQuery(quantityType: healthKitManager.distanceCount!, quantitySamplePredicate: predicate, options: sumOption) {
[unowned self] (query, result, error) in
if let sumQuantity = result?.sumQuantity() {
dispatch_async(dispatch_get_main_queue(), {
let totalDistance = sumQuantity.doubleValueForUnit(self.healthKitManager.distanceUnit)
self.distanceTotalLength = totalDistance
completion() // <----- call the closure here
})
}
}
healthKitManager.healthStore?.executeQuery(statisticsSumQuery)
}
// Then whenever you need to update the distance sum call the function
// with the closure, then handle the result as needed
queryDistanceSum { () -> () in
// distanceTotalLength has now been set.
// Update UI for new distance value or whatever you need to do
}
每当实现闭包时,都必须假定闭包中的代码将在以后执行。