What does CMErrorDomain error 103. mean? (CMPedometer) - ios

I'm struggling totally to get CMPedometer to return any step data. However Iconfigure I get Error Domain=CMErrorDomain Code=103 "The operation couldn’t be completed. (CMErrorDomain error 103.)"
I'm using swift and have broken down the queryPedometerDataFromDate query to be as simple as possible.
let pedometer = CMPedometer()
let fromDateString = "2015-01-22"
let toDateString = "2015-01-23"
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "YYYY-MM-DD"
let fromDate = dateFormatter.dateFromString(fromDateString)
let toDate = dateFormatter.dateFromString(toDateString)
pedometer.queryPedometerDataFromDate(fromDate, toDate: toDate) { (data:CMPedometerData!, error:NSError!) -> Void in
if error == nil {
println(data)
} else {
println(error)
}
}
I've enabled motion detection for my app, and have no problem getting similar data out of HealthKit.
I must be missing something simple, but I can't see what it is!

Ok, so after another day of research. You have to have the CMPedometer object as a global variable for your class. If it's defined as a local variable like in the question it won't work. Simply adding let pedometer = CDPedometer() at the class level will fix this issue.

Related

HKUnit for HKBloodGlucose in HealthKit with Swift

My name is Shak. I'm an iOS developer.
Recently, I started learning HealthKit and after some progress I have a problem which I need some help. Here is my problem:
I've been trying to save blood glucose data to healthKit but I'm getting this error that "Cannot convert value of type 'HKUnit.Type' to expected argument type 'HKUnit'". Here is the code:
let bloodGlucoseQuantity = HKQuantity(unit: HKUnit, doubleValue: Double(bloodGlucose))
func saveBloodGlucoseSample(bloodGlucose: Int, date: Date) {
guard let bloodGlucoseType = HKQuantityType.quantityType(forIdentifier: .bloodGlucose) else {
fatalError("Blood glucose type is not longer available in HealthKit")
}
let bloodGlucoseQuantity = HKQuantity(unit: HKUnit, doubleValue: Double(bloodGlucose))
let bloodGlucoseSample = HKQuantitySample(type: bloodGlucoseType, quantity: bloodGlucoseQuantity, start: date, end: date)
HKStore?.save(bloodGlucoseSample) { success, error in
if let error = error {
print("Error saving blood glucose sample: \(error.localizedDescription)")
} else {
print("Successfully saved blood glucose sample")
}
}
}
If anyone has any experience with HealthKit and specifically with blood glucose type I'll be grateful if you can help me.
let bloodGlucoseQuantity = HKQuantity(unit: HKUnit, doubleValue: Double(bloodGlucose))
You need to use a proper HKUnit instance and not just pass the class. e.g. pass HKUnit(from: "mg/dL") to unit.
I have developed the same application in Xamarin.forms. We have to pass the actual HKUnit instance and not the direct class. In xamarin.forms I have passed
HKUnit.CreateMoleUnit(HKMetricPrefix.Milli,HKUnit.MolarMassBloodGlucose).UnitDividedBy(HKUnit.Liter)
you have to convert this code in swift and you are good to go.!

Intermittent crash when performing fetch on core data

I have a published app that is occasionally crashing when performing a core data fetch. I know where the crashes are occurring, however I can't figure out why they are happening.
The app uses a tab view controller, and the crash occurs in a tab that has a tableView as the initial view. Because I need this tableView to update whenever data is changed elsewhere in the app, I'm performing a fetch in the viewWillAppear method.
Here is the relevant code:
lazy var fetchedResultsController: NSFetchedResultsController<Day> = {
let request: NSFetchRequest<Day> = Day.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(key: "date", ascending: false)]
request.predicate = NSPredicate(format: "calories > %#", "0")
let frc = NSFetchedResultsController(fetchRequest: request, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
return frc
}()
override func viewWillAppear(_ animated: Bool) {
do {
try fetchedResultsController.performFetch()
} catch {
print("Could not fetch results")
}
tableView.reloadData()
}
And here is an image of the call stack.
I haven't been able to recreate the crash on my device or on the simulator, so I really don't know how to go about fixing this bug. I'd appreciate any advice on solving this.
Here's a screenshot of the calories attribute in the core data model.
Here's the class method for creating a Day entity.
class func dayWithInfo(date: Date, inManagedContext context: NSManagedObjectContext) -> Day {
let defaults = UserDefaults.standard
let formatter = DateFormatter()
formatter.dateStyle = .full
let dateString = formatter.string(from: date)
let request: NSFetchRequest<Day> = Day.fetchRequest()
request.predicate = NSPredicate(format: "dateString = %#", dateString)
if let day = (try? context.fetch(request))?.first {
if let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: Date()) {
// Update the macro goals if the date is the current or future date
if date > yesterday {
day.proteinGoal = defaults.double(forKey: Constants.UserDefaultKeys.proteinValueKey)
day.carbohydrateGoal = defaults.double(forKey: Constants.UserDefaultKeys.carbohydratesValueKey)
day.lipidGoal = defaults.double(forKey: Constants.UserDefaultKeys.lipidsValueKey)
day.fiberGoal = defaults.double(forKey: Constants.UserDefaultKeys.fiberValueKey)
day.calorieGoal = defaults.double(forKey: Constants.UserDefaultKeys.caloriesValueKey)
}
}
return day
} else {
let day = Day(context: context)
// Set the date as a string representation of a day
day.dateString = dateString
day.date = date
// Set the calorie and macronutrient goals from user defaults
day.proteinGoal = defaults.double(forKey: Constants.UserDefaultKeys.proteinValueKey)
day.carbohydrateGoal = defaults.double(forKey: Constants.UserDefaultKeys.carbohydratesValueKey)
day.lipidGoal = defaults.double(forKey: Constants.UserDefaultKeys.lipidsValueKey)
day.fiberGoal = defaults.double(forKey: Constants.UserDefaultKeys.fiberValueKey)
day.calorieGoal = defaults.double(forKey: Constants.UserDefaultKeys.caloriesValueKey)
// Creat meals and add their ralationship to the day
if let meals = defaults.array(forKey: Constants.UserDefaultKeys.meals) as? [String] {
for (index, name) in meals.enumerated() {
_ = Meal.mealWithInfo(name: name, day: day, slot: index, inManagedContext: context)
}
}
return day
}
}
Allow me to posit a theory about what I think is happening. I might be making incorrect assumptions about your project, so please correct anything I get wrong. You likely understand all the below, but I'm trying to be thorough, so please excuse anything obvious.
You have a calories attribute of your model class that is implemented as an optional attribute with no default at the model level. Something like the below.
You also do not implement func validateCalories(calories: AutoreleasingUnsafeMutablePointer<AnyObject?>, error: NSErrorPointer) -> Bool in your managed object subclass, so it's possible to save an instance with a nil (remember that Core Data is still Objective-C, so your Double Swift attribute is an NSNumber in Core Data, so nil is perfectly valid for an optional attribute).
You can specify that an attribute is optional — that is, it is not required to have a value. In general, however, you are discouraged from doing so — especially for numeric values (typically you can get better results using a mandatory attribute with a default value — in the model — of 0). The reason for this is that SQL has special comparison behavior for NULL that is unlike Objective-C's nil. NULL in a database is not the same as 0, and searches for 0 will not match columns with NULL.
At this point, it would be easy to confirm the hypothesis. Simply edit the SQLite database used for Core Data by your app in the simulator and set the calories attribute of a single record to null and see if you crash in the same way.
If so, do a Core Data migration on your next release and remove the Optional designation on the model attribute and provide a Default value of zero.

What is a closure #1 error in swift?

I am having trouble debugging this error. I use Crashlytics on my iOS app and have been seeing this error in a few of my apps. Here is part of the stack trace:
Here is my code inside of BusStopTimesViewController.swift (I comment what is line 140 since that seems to be where the problem is happening according to the trace):
func loadBusData(_ busUrl: String) {
let urlString = busUrl
let url = URL(string: urlString)!
...
if passingTimePredicted != "" {
let nextBusDate = dateFormatter.date(from: passingTimePredicted)
// THE FOLLOWING LINE IS LINE 140
var minutesUntilBus = (nextBusDate!.timeIntervalSince1970 - Date().timeIntervalSince1970) / 60
let calendar = Calendar.current
let hour = calendar.component(.hour, from: nextBusDate!)
let minutes = calendar.component(.minute, from: nextBusDate!)
...
}
}
My initial thought is it is because nextBusDate is nil and I am trying to work with it, but I don't think that is it because the error says nothing about nextBusDate being nil (although I should probably check if it is nil before working with it). I am confused on what this error about (closure #1) is? Any thoughts would be greatly appreciated.

Delete health data that was previous stored from the same app in Swift?

Update Oct 7th
So after I read the answer, I now understand that I need to using query to retrive the data in Health and I try to using with codes:
let deletedType = HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier.dietaryCaffeine)
let predicate = HKQuery.predicateForSamples(withStart: dataDate as Date, end: dataDate as Date, options: .strictStartDate)
let findQuery = HKSampleQuery(sampleType: deletedType!, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: nil) {
query, results, error in
if results != nil {
print("\nHere we got not nil on results!\n")
for result in (results as? [HKQuantitySample])! {
let quantity = result.quantity.doubleValue(for: HKUnit.gramUnit(with: .milli))
print(quantity)
}
} else {
print("results are nil")
return
}
}
healthKitStore.execute(findQuery)
I didn't do lot in the resultHander block, I firstly want to check what Data I found, and when I pring the quantity, I got noting, but I did get the "Here we got not nil on resluts" which means the results is not nil. I'm fresh to iOS developing and I check the document of HKHealthSample and cannot find which part of my HKSampleQuery wrong!
Original One:
I have an app that writes caffeine data into Health via HealthKit
Here is the save function
func saveCaffeine(_ caffeineRecorded: Double, dataDate: Date) {
// Set the quantity type to the running/walking distance.
let caffeineType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.dietaryCaffeine)
// Set the unit of measurement to miles.
let caffeineQuantity = HKQuantity(unit: HKUnit.gramUnit(with: .milli), doubleValue: caffeineRecorded)
// Set the official Quantity Sample.
let caffeine = HKQuantitySample(type: caffeineType!, quantity: caffeineQuantity, start: dataDate, end: dataDate)
print("\n to be added: \(caffeine) \n")
// Save the distance quantity sample to the HealthKit Store.
healthKitStore.save(caffeine, withCompletion: { (success, error) -> Void in
if( error != nil ) {
print(error!)
} else {
print("The Caffeine has been recorded! Better go check!")
}
})
}
Then It saved succeddfully, after that I retrive the data when I delete from the table view and pass to another delete function :
func deleteCaffeine(_ caffeineRecorded: Double, dataDate: Date){
let caffeineType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.dietaryCaffeine)
let caffeineQuantity = HKQuantity(unit: HKUnit.gramUnit(with: .milli), doubleValue: caffeineRecorded)
let coffeeBeenDeleted = HKQuantitySample(type: caffeineType!, quantity: caffeineQuantity, start: dataDate, end: dataDate)
print("\n to be deleted: \(coffeeBeenDeleted) \n")
healthKitStore.delete(coffeeBeenDeleted, withCompletion: {(success, error) -> Void in
if (error != nil) {
print(error!)
} else {
print("This caffeine data just been deleted!")
}
})
}
Then I got the error: Error Domain=com.apple.healthkit Code=3 "Failed to find some objects for deletion."
I using Realm to manage the database, I write the data into it that I can then retrieve it.
When I add it the HQuantitySample been printed is:
to be added: 30 mg (2017-10-06 18:36:25 -0400 - 2017-10-06 18:36:25 -0400)
When I delete the same one, the HQuantitySample been printed is: to be deleted: 30 mg (2017-10-06 18:36:25 -0400 - 2017-10-06 18:36:25 -0400)
As I understand, it should retrieve the same data since the amount and date is all right. Am I misunderstand anything about delete in HealthKit
You can't delete an HKQuantitySample that was previously saved by constructing a new HKQuantitySample that has similar properties. If there were two caffeine samples in HealthKit with the same start date, end date, and quantity which one would you expect HealthKit to delete? Each HKObject is unique and to delete an object you must first find it using a query and then pass the object you got from the query to delete().
You need to define your specific key in HKMetadataKeySyncIdentifier before you save your data to apple health. And then, you can use HKMetadataKeySyncIdentifier to delete specific health data.
You can try my answer:
https://stackoverflow.com/a/69624769/8094919

Create new HKQuantityType

I've read in some pages that you can add custom samples to HealthKit in order to have another measurements saved.
In my case, I want to add accelerometer data from the apple watch to HealthKit.
This is my code
func saveSample(data:Double, date:NSDate ) {
let dataType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.init(rawValue: "acc"))
let dataQuantity = HKQuantity(unit: HKUnit.init(from: "m/s^2"), doubleValue: data)
let dataSample = HKQuantitySample(type: dataType!, quantity: dataQuantity, start: date as Date, end: date as Date)
healthKitStore.save(dataSample, withCompletion: { (success, error) -> Void in
if( error != nil ) {
print("Error saving sample:")
} else {
print("Sample saved successfully!")
}
})
}
I want to add a sample called "acc" (in a normal case one example of this could be "bloodPreasure") with unit "m/s^2".
I get nil on dataType, so then I get this Error on let dataSample = HKQuantitySample(type: dataType!, quantity: dataQuantity, start: date as Date, end: date as Date) line, because dataType is nil.
fatal error: unexpectedly found nil while unwrapping an Optional value
Any ideas,How to implement this? Thank u all!
I believe for HKQuantityType.quantityType(forIdentifier: we need to provide identifier provided by apple like HKQuantityTypeIdentifier.bodyTemperature. And then only it will return an object of quantityType.
So you are getting nil in dataType.
And I believe we can't create new HKQuantityType because health store will have to save it too, and that part is not in our control.

Resources