jennykz
jennykz

Reputation: 11

How to fix this error: 'Foundation._GenericObjCError error 0. '

I'm trying to build an app which reads data from the Apple Health App.

My app asks for the user's permission to access data from HealthKit. When I try to read the data after granting the app permission, I get this error message:

The operation couldn't be completed. (Foundation._GenericObjCError error 0.)

No errors show up on Xcode; this message only appears when testing on a device.

This is the portion of the code which gets permission from HealthKit:

import Foundation

import HealthKit

class HealthKitSetupAssistant{

    private enum HealthkitSetupError: Error{
        case notAvailableOnDevice
        case dataTypeNotAvailable
    }

    class func authorizeHealthKit(completion: @escaping (Bool, Error?) -> Swift.Void){

        // 1. Check to see if HealthKit is available on this device
        guard HKHealthStore.isHealthDataAvailable() else{
            completion(false, HealthkitSetupError.notAvailableOnDevice)
            return
        }

        //2. Prepare the data types that will interact with HealthKit
        guard   let dateOfBirth = HKObjectType.characteristicType(forIdentifier: .dateOfBirth),
            let bloodType = HKObjectType.characteristicType(forIdentifier: .bloodType),
            let biologicalSex = HKObjectType.characteristicType(forIdentifier: .biologicalSex),
            let bodyMassIndex = HKObjectType.quantityType(forIdentifier: .bodyMassIndex),
            let height = HKObjectType.quantityType(forIdentifier: .height),
            let bodyMass = HKObjectType.quantityType(forIdentifier: .bodyMass),
            let activeEnergy = HKObjectType.quantityType(forIdentifier: .activeEnergyBurned) else{

                completion(false, HealthkitSetupError.dataTypeNotAvailable)
                return
        }

        //3. Prepare a list of types you want HealthKit to read and write
        let healthKitTypesToWrite: Set<HKSampleType> = [bodyMassIndex, activeEnergy, HKObjectType.workoutType()]

        let healthKitTypesToRead: Set<HKObjectType> = [dateOfBirth, bloodType, biologicalSex, bodyMassIndex, height, bodyMass, HKObjectType.workoutType()]

        //4. Request Authorization
        HKHealthStore().requestAuthorization(toShare: healthKitTypesToWrite, read: healthKitTypesToRead) { (success, error) in
            completion(success, error)

        }
    }
}

This is the portion of the code which tries to read data from HealthKit:

import Foundation
import HealthKit

class ProfileDataStore {

    class func getAgeSexAndBloodType() throws -> (age: Int,
        biologicalSex: HKBiologicalSex,
        bloodType: HKBloodType) {

            let healthKitStore = HKHealthStore()

            do {

                //1. This method throws an error if these data are not available.
                let birthdayComponents =  try healthKitStore.dateOfBirthComponents()
                let biologicalSex =       try healthKitStore.biologicalSex()
                let bloodType =           try healthKitStore.bloodType()

                //2. Use Calendar to calculate age.
                let today = Date()
                let calendar = Calendar.current
                let todayDateComponents = calendar.dateComponents([.year],
                                                                  from: today)
                let thisYear = todayDateComponents.year!
                let age = thisYear - birthdayComponents.year!

                //3. Unwrap the wrappers to get the underlying enum values.
                let unwrappedBiologicalSex = biologicalSex.biologicalSex
                let unwrappedBloodType = bloodType.bloodType

                return (age, unwrappedBiologicalSex, unwrappedBloodType)
            }
    }

    class func getMostRecentSample(for sampleType: HKSampleType,
                                   completion: @escaping (HKQuantitySample?, Error?) -> Swift.Void) {

        //1. Use HKQuery to load the most recent samples.
        let mostRecentPredicate = HKQuery.predicateForSamples(withStart: Date.distantPast,
                                                              end: Date(),
                                                              options: .strictEndDate)

        let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate,
                                              ascending: false)

        let limit = 1

        let sampleQuery = HKSampleQuery(sampleType: sampleType,
                                        predicate: mostRecentPredicate,
                                        limit: limit,
                                        sortDescriptors: [sortDescriptor]) { (query, samples, error) in

                                            //2. Always dispatch to the main thread when complete.
                                            DispatchQueue.main.async {

                                                guard let samples = samples,
                                                    let mostRecentSample = samples.first as? HKQuantitySample else {

                                                        completion(nil, error)
                                                        return
                                                }

                                                completion(mostRecentSample, nil)
                                            }
        }

        HKHealthStore().execute(sampleQuery)
    }

    class func saveBodyMassIndexSample(bodyMassIndex: Double, date: Date) {

        //1.  Make sure the body mass type exists
        guard let bodyMassIndexType = HKQuantityType.quantityType(forIdentifier: .bodyMassIndex) else {
            fatalError("Body Mass Index Type is no longer available in HealthKit")
        }

        //2.  Use the Count HKUnit to create a body mass quantity
        let bodyMassQuantity = HKQuantity(unit: HKUnit.count(),
                                          doubleValue: bodyMassIndex)

        let bodyMassIndexSample = HKQuantitySample(type: bodyMassIndexType,
                                                   quantity: bodyMassQuantity,
                                                   start: date,
                                                   end: date)

        //3.  Save the same to HealthKit
        HKHealthStore().save(bodyMassIndexSample) { (success, error) in

            if let error = error {
                print("Error Saving BMI Sample: \(error.localizedDescription)")
            } else {
                print("Successfully saved BMI Sample")
            }
        }
    }
}

Any suggestions or explanation of the error messages would be appreciated!

Upvotes: 1

Views: 5047

Answers (3)

Kang Developer
Kang Developer

Reputation: 83

Check your account type. The same error occurred when I used the'Enterprise' account. After changing to a general developer account, it was found that it worked normally.

Upvotes: 0

Pablo Vi&#241;als
Pablo Vi&#241;als

Reputation: 131

Not sure if you still have this error, but I had the same one. I didnt have the data filled in in emulator's Health App, so when I tried to retrieve the data, the error appeared.

I filled the the data in emulator's Health App and then I tried again and it worked.

Hope it helps.

Upvotes: 0

Joakim Danielson
Joakim Danielson

Reputation: 52053

Your supposed to create only one instance of HKHealthStore in your app and reuse that instance. I don’t know how your app is structured so I don’t know where is the best place is to keep a reference to HKHealthStore but AppDelegate is always an option.

Upvotes: 0

Related Questions