Ошибка 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")
}
}
Пожалуйста, убедитесь, что вы выполнили все следующие шаги:
- Добавлять
Health entitlement
в вашем приложении. - Добавлять
Usage description
тексты в вашемInfo.plist
- Запросить авторизацию
- Предоставьте авторизацию
- Сохраните некоторые действительные образцы данных
- Запросить данные
- Проверить, не является ли результат пустым и допустимым
- Удалить полученные данные