How to read different workouts in HEALTHKIT SWIFT? - ios

I’m new in Swift and I need to extract all data related to workouts from HealthKit and use it in JavaScript (I'm making a React Native app), so I made a query but its predicate only pass one workout e.g .cycling, what I need is to get all workouts, even if the user has it or not, let's say: get all workouts recorded (even if they are differents) by the user in a list.
I need: Running {...} Cycling {....} Pilates {...}
but I'm getting : Cycling 1 Cycling 2 Cycling 3
In brief, I need a predicate to do this. my code:

You should be passing a nil predicate to the HKSampleQuery to retrieve all workouts regardless of their type.

Related

Realm Swift: Question about Query-based public database

I’ve seen all around the documentation that Query-based sync is deprecated, so I’m wondering how should I got about my situation:
In my app (using Realm Cloud), I have a list of User objects with some information about each user, like their username. Upon user login (using Firebase), I need to check the whole User database to see if their username is unique. If I make this common realm using Full Sync, then all the users would synchronize and cache the whole database for each change right? How can I prevent that, if I only want the users to get a list of other users’ information at a certain point, without caching or re-synchronizing anything?
I know it's a possible duplicate of this question, but things have probably changed in four years.
The new MongoDB Realm gives you access to server level functions. This feature would allow you to query the list of existing users (for example) for a specific user name and return true if found or false if not (there are other options as well).
Check out the Functions documentation and there are some examples of how to call it from macOS/iOS in the Call a function section
I don't know the use case or what your objects look like but an example function to calculate a sum would like something like this. This sums the first two elements in the array and returns their result;
your_realm_app.functions.sum([1, 2]) { sum, error in
if let err = error {
print(err.localizedDescription)
return
}
if case let .double(x) = result {
print(x)
}
}

Chat app logic with Swift and Firebase

I'm implementing chat logic 1-1 in my iOS app. I'm using firebase to store chats and messages in chats. Messages are working great. But I have some difficulties with chats list.
My structure of stored chats looks like this
-Users
--UserID
---chatrooms
----chatroomID
-----updatedTime
-----deleted
-----read
-----receiverID
-----receiverName
I store in NSUserDefaults NSDate value "chatsLoadedTime". I query chats by sending query:
var time: String?
if defaults.valueForKey("chatsLoadedTime") != nil {
time = "\(defaults.valueForKey("chatsLoadedTime") as! NSDate)"
}
chatsRef.queryOrderedByChild("createdTime").queryStartingAtValue(time).observeEventType(.Value, withBlock: { snap in
defaults.setValue(toLocalTime(NSDate()), forKey: "chatsLoadedTime")
and so on
.
.
.
As far as I can see it is a good way to store chats and be able to download chats from different devices. For example I have just installed the app, my chatsLoadedTime value is nil, then I download all chats and update this value to current dateTime. If new chat created, then its createdTime is bigger then my chatsLoadedTime value and the app will download it.
But I don't know how to implement a good and efficient way to delete chat. I want this logic: if user1 delete chat, then he just change his value deleted=true. If second user also delete this chat at his side, then the chat and the messages will be totally removed from the app. If user1 deleted chat, but user2 not, then if user2 write to user1, then user1 receives this messages and all previous, because messages weren't deleted. But maybe it is not the best logic. Give m, please an advice how to do this in the best way.
If I could, I would want to query on multiple values, but as far as I know it is not possible.
I've added updatedTime value to every chatRoom. And I've added a value to device called lastLoadedTime. Every time when i receive snapshot from firebase i update lastLoadedTime to current time. So, I observe chats, where time value stored on the device is smaller than updatedTime in chatRoom in firebase. When i delete chat i set updated time to 1990-01-01 00:00:00. So i won't observe this chat until somebody send me a message. Ask me if you need more information to understand :)

Is HKMetadataKeyWasUserEntered broken? I keep getting nil when there is data in the health app

I'm trying to grab data from the Health App. Specifically data that the user did not enter in themselves. For instance, I have an iPhone 6+ that logs the amount of steps that I take. There is also an option to add the data manually; If you add the data manually, the health app marks the data as "user added".
Here's what's confusing me. Let's say I added a step count of 22. When I query the data using HKStatisticsQuery with a predicate of
HKQuery.predicateForObjectsWithMetadataKey(HKMetadataKeyWasUserEntered, allowedValues: [true])
I get the correct result of 22 steps, since I set the allowedValues to true and that I added this myself. However, when I try to set allowedValues to false, I get no results
HKQuery.predicateForObjectsWithMetadataKey(HKMetadataKeyWasUserEntered, allowedValues: [false])
I do indeed have the step data in the health app, but it returned no results.
Check for the below possible areas to fix it:
did you authorized your application to access Steps data from HealthKit?
If your quering for steps count from your application without authorizing with HealthKit, then HealthKit will not return any exception it will simply returns the steps count which was entered from your application only if available, otherwise returns nil.
Before going to query health data, check for the authorization status for steps count using authorizationStatusForType: method available with HKHealthStore class.
Update 1:
My observations on wasUserEntered key is:
If user entering steps data from HEALTH app, respective HKQuantitySample stores metadata dictionary along with HKWasUserEntered key as TRUE automatically.
If user entering steps data from other than Apple's HEALTH app, respective health/fitness device or our application should send metadata dictionary with key HKWasUserEntered along with value as either TRUE/FALSE. Otherwise, the metadata property will contain nil object. Hence, Apple is not applying predicate(predicate contains metadata key) on the data which don't have metadata with it.
For debugging this metadata, try to print your HKQuantitySampleObject.metadata
Apple's implementation on metadata Vs NSPredicate:
If Health data observed from Health/fitness devices, HealthKit is not adding the metadata dictionary to the respective health record.
In case of Health applications other than Apple's Health app, the developer should manually add the metadata dictionary for his record of health data.
If there is no metadata for a specific health record and NSPredicate have a constraint on metadata then, HealthKit completely omitting to validate such records.
Finally,
It is advised to use
(instancetype)quantitySampleWithType:(HKQuantityType *)quantityType
quantity:(HKQuantity *)quantity
startDate:(NSDate *)startDate
endDate:(NSDate *)endDate
metadata:(NSDictionary *)metadata;
instead of
+ (instancetype)quantitySampleWithType:(HKQuantityType *)quantityType
quantity:(HKQuantity *)quantity
startDate:(NSDate *)startDate
endDate:(NSDate *)endDate;
to add metadata.
Reporting Apple regarding this bug that, predicate(which contains metadata key) should be applied on all the data irrespective of checking for metadata exists or not.
It's been a while and you have probably solved this by now, but I think it is worth posting here in case someone else comes across the same issue.
Like Bhanu mentioned, data created by Apple themselves doesn't seem to have the HKWasUserEntered entry as part of its metadata.
But Apple never claims to do it anyway in their docs, so the proper query would be one that filtered out items with HKWasUserEntered == true if that key was set, but also gave back everything else that had no metadata associated.
The ideia is that metadata is a Dictionary, and that type returns nil if a key does not exist. So there are three possible scenarios:
HKMetadataKeyWasUserEntered == nil
HKMetadataKeyWasUserEntered == false
HKMetadataKeyWasUserEntered == true
Out of those, you just want to filter out the last one, since that explicitly tells you that data was entered but the user.
This can be done using the + predicateForObjectsWithMetadataKey:operatorType:value: convenience method on HKQuery, like this:
HKQuery.predicateForObjects(withMetadataKey: HKMetadataKeyWasUserEntered, operatorType: .notEqualTo, value: true)
But of course, your initial question was: "Is HKMetadataKeyWasUserEntered broken?". And I don't believe it is, since, like mentioned, Apple never claims to write that key for their own values. :)

Core data fetch relational object

Im very newbie to iOS programming.
I have core data app for tasks with two entities: Group and Task.
User creates task groups like Work, Home, Shoping and tasks related to these groups like for Work-Deploy an app, for Shopping-buy milk etc.
I have two view controllers.
Problem is that now when user clicks on a Group in tableView, it gets to next viewController, where tasks from all groups are listed. So, how I could show only Group (selected in tableView) related Tasks?
For now when for exapmle I click on Work group I see Deploy an app and Buy milk etc tasks.. I guess its something wrong with NSFetchRequest or NSPredicate Thanks!
Create an NSPredicate to have task == the task from selected cell. Use this predicate filter the the NSSet that you get when asking for the tasks property on the group-class.
If you already did this, please show the code that is doing this, so we can see what exactly is that is going wrong.
Can you also give a screenshot of (the relevant part of) your model and indicate whether you have NSManagedObject subclasses for the entities?

One query for two core data relationships?

I have the following data model:
And I'd like to have a property on the playlist object that points to its list of songs. Right now I have something like:
self.songs = [self.playlistMemberships valueForKey:#"song"];
But I'm noticing that this is very slow and core data seems to be firing off faults for each individual song. Any thoughts on how to make a single call to pull all the song info? Thanks!
PlaylistMembership just seems to get in the way -- can you relate Playlist to Song directly and cut out the PlaylistMembership? I think that'd let Core Data fetch all the songs at once rather than fetching all the memberships and then having to go back to get each song.
If you can't or prefer not to get rid of the membership entity, use setRelationshipKeyPathsForPrefetching: to specify that song should be fetched along with the membership.

Resources