HealthKit thread crashes on nopl command after successfully running

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 comment 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.

Replies

It seems that the issue is with accessing self. Is it the same object after the view appears the 2nd time? Have you tried replacing unowned with weak? Also you're using startTime and delegate from the HealthKit queue, which I believe is the different one from where you set them, so if they aren't constants they're worth to add some synchronisation code.