Ошибка HealthKit: «Не удалось найти некоторые объекты для удаления» при попытке удалить HKQuantitySample

У меня есть приложение Apple Watch для тренировок, которое запускаетHKWorkoutи сохраняетHKQuantitySamples(примеры DistanceWalkingRunning) в Apple Health с использованием исходного API Healthkit (а не более нового конструктора тренировок). Затем я хочу дать пользователю возможность удалить их в сопутствующем приложении для iPhone (например, они забыли завершить тренировку на часах). Независимо от того, какой из 3 методов удаления образцов я использую ниже, я всегда получаю эту ошибку. Я знаю, что приложение может удалять только сэмплы, которые были сохранены этим же приложением, но тот факт, чтоHKSourceиз образцов приложение для часов не позволяет мне удалить их на iPhone? Я бы не подумал, что это было задумано. Есть ли другая причина, по которой я не могу удалить эти образцы?

      private func deleteRunningAndWalkingSamplesFrom(startDate: Date, endDate: Date) {
        
        let healthStore = HKHealthStore()
        
        guard let distanceWalkingAndRunningType:HKQuantityType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.distanceWalkingRunning) else {
            return
        }
        
        let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate)
        
        let distanceWalkingAndRunningQuery = HKSampleQuery(sampleType: distanceWalkingAndRunningType,
                                                           predicate: predicate,
                                                           limit: (HKObjectQueryNoLimit),
                                                           sortDescriptors: nil)
        { (query:HKSampleQuery, results:[HKSample]?, error:Error?) -> Void in
            
            if let unwrappedError = error {
                print("Error trying to delete distance samples = \(unwrappedError)")
                return 
            }
            
            guard let unwrappedResults = results as? [HKQuantitySample] else {
                print("Couldn't cast results as [HKQuantitySample] in deleteRunninAndWalkingSamples")
                return
            }
       
//(1) Look through samples and try to delete   
//            for sample in unwrappedResults {
//                healthStore.delete(sample) { success, error in
//                    if let error = error {
//                        print("error attempting to delete runningAndWalkinGSample with startDate of \(sample.startDate) error = \(error)")
//                    }
//
//                    if success {
//                        print("successfully delete sample with startDate of \(sample.startDate)")
//                    }
//                }
//            }
 
//(2) Delete objects with predicate                
//            healthStore.deleteObjects(of: distanceWalkingAndRunningType, predicate: predicate) { success, deleteCount, error in
//                if let error = error {
//                    print("error attempting to delete runningAndWalkinGSamplesFrom shift = \(error)")
//                }
//
//                if success {
//                    print("successfully deleted \(deleteCount) samples")
//                }
//            }
            
        
       //(3) Delete all samples        
       healthStore.delete(unwrappedResults) { success, error in
                if let error = error {
                    print("error attempting to delete runningAndWalkinGSamplesFrom shift = \(error)")
                }

                if success {
                    print("success deleting runningAndWalkingSamples ")
                    
                }

            }
            
        }
        healthStore.execute(distanceWalkingAndRunningQuery)
            
            
        
        
    }

1 ответ

Я создал пример приложения и не смог воспроизвести проблему:

      import SwiftUI
import HealthKit

final class HealthManager: ObservableObject {
    let quantityType = HKQuantityType.quantityType(forIdentifier: .distanceWalkingRunning)!
    let healthStore = HKHealthStore()
    
    func requestAuthorization() {
        healthStore.requestAuthorization(toShare: [quantityType], read: [quantityType]) { [weak self] success, error in
            print(success, error?.localizedDescription ?? "")

            self?.createMockData { [weak self] success, error in
                print(success, error?.localizedDescription ?? "")

                self?.deleteMockData { success, error in
                    print(success, error?.localizedDescription ?? "")
                }
            }
        }
    }
    
    func createMockData(completion: @escaping (Bool, Error?) -> ()) {
        let sample = HKQuantitySample(type: quantityType,
                                      quantity: .init(unit: .inch(), doubleValue: 1000),
                                      start: Date().addingTimeInterval(-1000),
                                      end: Date().addingTimeInterval(-10))
        healthStore.save(sample, withCompletion: completion)
    }
    
    func deleteMockData(completion: @escaping (Bool, Error?) -> ()) {
        let predicate = HKQuery.predicateForSamples(withStart: .distantPast, end: .distantFuture)
        let distanceWalkingAndRunningQuery = HKSampleQuery(sampleType: quantityType,
                                                           predicate: predicate,
                                                           limit: HKObjectQueryNoLimit,
                                                           sortDescriptors: nil) { [weak self] (query, results, error) in

            if let unwrappedError = error {
                completion(false, unwrappedError)
                return
            }
            
            guard let unwrappedResults = results as? [HKQuantitySample] else {
                completion(false, NSError(domain: "dom", code: 1, userInfo: [
                    NSLocalizedDescriptionKey: "Couldn't cast results as [HKQuantitySample] in deleteRunninAndWalkingSamples"
                ]))
                
                return
            }
            
            guard !unwrappedResults.isEmpty else {
                completion(false, NSError(domain: "dom", code: 2, userInfo: [
                    NSLocalizedDescriptionKey: "Nothing to delete"
                ]))
                
                return
            }

            self?.healthStore.delete(unwrappedResults, withCompletion: completion)
        }
        
        healthStore.execute(distanceWalkingAndRunningQuery)
    }
}


@main
struct TestApp: App {
    @StateObject var healthManager = HealthManager()
    
    @SceneBuilder var body: some Scene {
        WindowGroup {
            NavigationView {
                ContentView()
                    .onAppear {
                        healthManager.requestAuthorization()
                    }
            }        
        }
        
        WKNotificationScene(controller: NotificationController.self, category: "myCategory")
    }
}

Пожалуйста, убедитесь, что вы выполнили все следующие шаги:

  1. ДобавлятьHealth entitlementв вашем приложении.
  2. ДобавлятьUsage descriptionтексты в вашемInfo.plist
  3. Запросить авторизацию
  4. Предоставьте авторизацию
  5. Сохраните некоторые действительные образцы данных
  6. Запросить данные
  7. Проверить, не является ли результат пустым и допустимым
  8. Удалить полученные данные
Другие вопросы по тегам