问题
I have a WatchKit app using HealthKit. When a view (with custom WKInterfaceController MonitorMetrics) appears it runs the following code:
func startRecordingHeartRate() {
let heartRateSample = HKSampleType.quantityType(forIdentifier:
HKQuantityTypeIdentifier.heartRate)
let heartRateUnit = HKUnit.count().unitDivided(by: HKUnit.minute())
let datePredicate = HKQuery.predicateForSamples(withStart: Date(), end: nil,
options: .strictStartDate)
let anchor: HKQueryAnchor? = nil
let updateHandler: (HKAnchoredObjectQuery, [HKSample]?, [HKDeletedObject]?, HKQueryAnchor?, Error?) -> () = {
[unowned self]
(query, newResult, deleted, newAnchor, error) in
if let samples = newResult as? [HKQuantitySample] {
guard samples.count > 0 else { return }
for sample in samples {
print("start of for loop")
let doubleSample = sample.quantity.doubleValue(for: heartRateUnit)
let timeSinceStart = sample.endDate.timeIntervalSince(self.startTime)
heartData[0].append(doubleSample)
heartData[1].append(Double(timeSinceStart))
self.delegate?.didRecieveHeartRate()
}
print("out of for loop")
self.updateHeartRateLabel()
}
}
let heartRateQuery = HKAnchoredObjectQuery(type: heartRateSample!,
predicate: datePredicate,
anchor: anchor,
limit: Int(HKObjectQueryNoLimit),
resultsHandler: updateHandler)
heartRateQuery.updateHandler = updateHandler
healthStore.execute(heartRateQuery)
}
func updateHeartRateLabel() {
print("update label")
let endIndex = heartData[0].endIndex
let lastHeartRate = heartData[0][endIndex-1]
self.heartRateLabel.setText(self.nf.string(from:NSNumber(value: lastHeartRate)) ?? "")
}
To pull heart rate data. Once it leaves this view it stops recording heart rate and resets the heartData arrays. When this view appears a second time it runs for one or two heart rates then crashes with a breakpoint on a nopl command in the HealthKit thread. (Since nopl is a no operation command I'm not sure how to interpret a crash there.)
As part of my attempt at debugging I've been commenting out various parts of the code. If I comment out everything in the sample for-loop and self.updateHeartRateLabel() it works without error. If I then uncomment updateHeartRateLabel() it crashes like explained above. Now what is really strange is if I leave the call to updateHeartRateLabel() uncommented but comment out the entirety of the function so it is just
func updateHeartRateLabel() {
}
The program still crashes. But once I commented the call back out it runs fine even though the call isn't doing anything it's still causing a crash. Now if I comment the call back out and uncomment the doubleSample declaration it works but uncommenting the timeSinceStart declaration causes the crash just like before. And the call to the delegate is also causing the crash.
As far as I can tell when I bring the view into view the second time everything should be identical to how it was the first time it was ran. And it runs without problem the second time for one or two heart rate pulls before it crashes. Playing around with it it seems like startTime and delegate just disappear before it crashes. Calling:
print(delegate)
and
print(startTime)
both cause the crash. And delegate is an optional but the print does not give nil it just crashes as if the variable name "delegate" no longer exists.
Edit:
I never stoped the query with: healthKit.stop(query:). So a Class with several required variables was being deinitialized while updateHandler was still being run leading to it trying to reference non-existing data and crashing.
来源:https://stackoverflow.com/questions/45664116/healthkit-crashing-when-pulling-heart-rate-on-second-call-after-working-on-first