Exclude own samples from healthkit queries - ios

I'm writing an app that amongst other things, reads weight samples from HealthKit.
I'm also writing samples.
I'm trying to read the latest sample that isn't mine:
NSPredicate* non_fdct = [NSCompoundPredicate notPredicateWithSubpredicate:[HKQuery predicateForObjectsFromSource:[HKSource defaultSource]]];
NSSortDescriptor *last = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:NO];
HKSampleQuery* query = [[HKSampleQuery alloc] initWithSampleType:[HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass] predicate:non_fdct limit:1 sortDescriptors:#[last] resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) { ... };
But I'm getting my own samples if they are the latest samples.
Any idea?

The way you have constructed the non_fdct predicate is not quite correct. Try this instead:
NSPredicate *non_fdct = [NSPredicate predicateFromString:#"%K != %#", HKPredicateKeyPathSource, [HKSource defaultSource]];

Related

Sort Array of FetchedObjects From Core Data by Number of Reviews in Objective-C

I would like to sort an array of Reviews fetched from Core Data by the number of times a given book is reviewed. The Entity is reviews and the review entity has an attribute bookid. So for the following table:
reviewid|bookid|review
1|1|This is a great novel...
2|1|Wonderful novel
3|2|Ok biography.
4|3|Horrible romance
I would like to return an array that has bookid=1 at the top as it has two reviews whereas the others have one.
How can I do this using NSSortDescriptor?
I believe, you can do it to the array after the fetch using the following but it seems that it should be possible to do it directly in the core data results
NSEntityDescription * entity = [NSEntityDescription entityForName:#"Parent" inManagedObjectContext:self.managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:reviews];
NSError *error;
NSArray *results = [self.managedObjectContext executeFetchRequest:request error:&error];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"bookid.#count" ascending:NO];
NSArray *descriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
NSArray *sortedArray = [results sortedArrayUsingDescriptors:descriptors];
You can set the NSFetchRequest's sort descriptor.
request.sortDescriptors = #[sortDescriptor]
Read the documentation for more info.
https://developer.apple.com/documentation/coredata/nsfetchrequest/1506262-sortdescriptors

iOS Healthkit reading workouts

Hi any one know how to fetch workouts data from HealthKit. i have seen in this tutorial http://www.raywenderlich.com/89733/healthkit-tutorial-with-swift-workouts it is in swift. i have tried in objective c based on that tutorial but getting results zero. there are questions for saving workouts but i want to read workouts data and display.
HKWorkoutType *workouttype = [HKWorkoutType workoutType];
HKWorkout *workout;
NSDate *startDate, *endDate;
NSDate *date1 = [NSDate date];
int daysTominus = -2;
startDate = [date1 dateByAddingTimeInterval:60*60*24*daysTominus];
int daysToAdd = 1;
NSDate *newDate1 = [date1 dateByAddingTimeInterval:60*60*24*daysToAdd];
endDate = newDate1;
workout = [HKWorkout workoutWithActivityType:HKWorkoutActivityTypeSwimming startDate:startDate endDate:endDate];
NSPredicate *predicate = [HKQuery predicateForObjectsFromWorkout:workout];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:YES];
HKSampleQuery *sampleQuery = [[HKSampleQuery alloc] initWithSampleType:workouttype
predicate:predicate
limit:HKObjectQueryNoLimit
sortDescriptors:#[sortDescriptor]
resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error)
{
if(!error && results){
for(HKQuantitySample *samples in results)
{
// your code here
NSLog(#"%#",samples);
}
}
}];
// Execute the query
[healthStore executeQuery:sampleQuery];
The problem seems to be your predicate.
This code works for me, I used running because I don't have swimming data but you can change it back to swimming:
-(void)retrieveWorkouts{
// 1. Predicate to read only running workouts
NSPredicate *predicate = [HKQuery predicateForWorkoutsWithWorkoutActivityType:HKWorkoutActivityTypeWalking];
// 2. Order the workouts by date
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]initWithKey:HKSampleSortIdentifierStartDate ascending:false];
// 3. Create the query
HKSampleQuery *sampleQuery = [[HKSampleQuery alloc] initWithSampleType:[HKWorkoutType workoutType]
predicate:predicate
limit:HKObjectQueryNoLimit
sortDescriptors:#[sortDescriptor]
resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error)
{
if(!error && results){
NSLog(#"Retrieved the following workouts");
for(HKQuantitySample *samples in results)
{
// your code here
HKWorkout *workout = (HKWorkout *)samples;
NSLog(#"%f",workout);
}
}else{
NSLog(#"Error retrieving workouts %#",error);
}
}];
// Execute the query
[healthStore executeQuery:sampleQuery];
}

Understanding results from HKSourceQuery, or Sources in general

I just did a HKSourceQuery and got some results. When I do a println of the results, I got this: <HKSource:0x156c1520 "Health" (com.apple.Health)>//description of the object
How do I use this to make a predicate using the HKQuery.predicateForObjectsFromSource(/* source goes here */)
Here is the sample code in Obj-c,
NSSortDescriptor *timeSortDesriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:NO];
HKQuantityType *quantityType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned];
HKSourceQuery *sourceQuery = [[HKSourceQuery alloc] initWithSampleType:quantityType samplePredicate:nil completionHandler:^(HKSourceQuery *query, NSSet *sources, NSError *error) {
//Here, sources is a set of all the HKSource objects available for "quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned"
HKSource *targetedSource = [[sources allObjects] firstObject];//Assume this as your targeted source
if(targetedSource)
{
NSPredicate *sourcePredicate = [HKQuery predicateForObjectsFromSource:targetedSource];
HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:quantityType predicate:sourcePredicate limit:HKObjectQueryNoLimit sortDescriptors:[NSArray arrayWithObject:timeSortDesriptor] resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) {
//results array contains the HKSampleSample objects, whose source is "targetedSource".
}];
[self.healthStore executeQuery:query];
}
}];
[self.healthStore executeQuery:sourceQuery];
UPDATE 1:
It is not possible to construct HKSource object manually using [HKSource alloc] init]. In HealthKit framework, Apple restricted creation of objects using init for most of the HK classes.
I believe that you can find your HKSource object from the sources set using the HKSource properties like name and bundleIdentifier.
Here is the sample code,
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.source.bundleIdentifier = 'com.XXXX.XXXXX'"];
NSArray *tempResults = [[sources allObjects] filteredArrayUsingPredicate:predicate];
HKSource *targetedSource = [tempResults firstObject];

Find Core Data Entities through two 1-to-1 relationships

Boundary <--> Datasets <-->> DataA
I want to find all Entities of DataA that belong to Boundary boundary1;
I tried:
NSPredicate *predication = [NSPredicate predicateWithFormant:#"datasets.boundary.boundaryID == %#", myBoundaryID];
but it has issue when trying to find the Boundary's properties.
My other thought was:
NSArray *savedAnalysis = [NSArray arrayWithArray:[dataset.savedAnalysis allObjects]];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:NAME ascending:TRUE];
NSArray *descriptors = [NSArray arrayWithObject:sortDescriptor];
self.datasourceSavedAnalysis = [NSArray arrayWithArray:[savedAnalysis sortedArrayUsingDescriptors:descriptors]];
But I don't know how to sort the Core Data Entities in the array.
I am not a database guy and I'm having trouble figuring out the logic to this stuff.
Try the following:
NSPredicate *predication = [NSPredicate predicateWithFormant:#"datasets.boundary == %#", myBoundary];
wWhere myBoundary is a Boundary entity.

NSSortDescriptor not working

I have a core data entity called "TruckNumber" which has a string as it's only property. The string is usually a 1-3 digit integer (as a string) but sometimes can have letters such as TMP9. The name of the property is "itsNotANumma". I am doing a fetch request to populate a picker, but they are not being sorted and I don't know why. I've used this exact technique on other entities for other pickers and never had a problem. Please help... Here's the relevant code:
// Fetch truck numbers
NSFetchRequest *truckNumberFetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *truckEntity = [NSEntityDescription entityForName:#"TruckNumber" inManagedObjectContext:self.managedObjectContext];
[truckNumberFetchRequest setEntity:truckEntity];
// Sort Descriptor
NSSortDescriptor *truckDescriptor = [[NSSortDescriptor alloc] initWithKey:#"itsNotANumma" ascending:YES];
NSArray *truckSortDescriptors = [[NSArray alloc] initWithObjects:truckDescriptor, nil];
[inventoryFetchRequest setSortDescriptors:truckSortDescriptors];
error = nil;
NSArray *truckResults = [managedObjectContext executeFetchRequest:truckNumberFetchRequest error:&error];
if (error)
NSLog(#"Unresolved error while saving context: %#, %#", error, [error userInfo]);
truckNumbersArray = [[NSMutableArray alloc] init];
for (TruckNumber *truckNumber in truckResults)
{
[truckNumbersArray addObject:truckNumber.itsNotANumma];
}
Here is my data model for truck number:
These are the results:
Looks like you have a simple typo:
[inventoryFetchRequest setSortDescriptors:truckSortDescriptors];
Should be:
[truckNumberFetchRequest setSortDescriptors:truckSortDescriptors];
I would assume anyway, from reading that code.
[NSSortDescriptor sortDescriptorWithKey:#"self" ascending:YES comparator:^(id obj1, id obj2){
return [(NSString*)obj1 compare:(NSString*)obj2 options:NSNumericSearch];
}];
It works so perfectly if you have numbers in a range from 1-5000 or onwards.

Resources