How to determine HKQuantitySample quantityType? - ios

I am trying to determine what kind of HKQuantityTypeIdentifier matches the measurements provided in a particular Health Kit sample To determine this, I have tried the following:
if(hkSample.quantityType == HKQuantityTypeIdentifierDistanceCycling) ...
if([hkSample.quantityType isEqual: HKQuantityTypeIdentifierDistanceCycling]) ...
and
if([hkSample.quantityType isEqualToString: HKQuantityTypeIdentifierDistanceCycling]) ...
The first two options run but give a negative result even when the types should be matching and the last option gives a run-time NSException error for an unknown method. What's the proper way to determine which type maths an HKQuantitySample type?

quantityType is an HKQuantityType, not a string, so it doesn’t respond to -isEqualToString:. You need to compare it with another HKQuantityType via -isEqual:, like this:
if ([hkSample.quantityType isEqual:[HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceCycling]])

Related

Object (Optional Any): get elements

I'm trying to pass information with an observed notification in my app.
The standard way to do that, is to set the userinfo. However, the data I want to pass is a Set, not a dictionary.
So, I do this:
NotificationCenter.default.post(name: MY_NOTIFICATION_NAME, object:self.productIds)
The object arrives fine, but now I'm unable to get to it:
in the console I do this:
po notification.object!
▿ 2 elements
- 0 : ZTJ
- 1 : ZTM
However, when I try to get to one of the elements, I get this:
po notification.object![0]
error: <EXPR>:8:21: error: value of type 'Any' has no subscripts
notification.object![0]
What am I doing wrong?
You know that notification.object is a Set, but the compiler doesn't because it's declared as Any, which means it could be anything, and so it can't find which implementation of object[0] it should use.
To read this object you need to cast it to a set.
if let mySet = notification.object as? Set<MyType> {
// Do whatever
}
Keep in mind that the object property of Notification is designed to be used as a filter, If you pass a value when adding an observer, you'll only get notifications that are sent with that exact same object.
The userInfo dictionary is to send related information, like your set. In this case I would send a dictionary like this:
NotificationCenter.default.post(name: MY_NOTIFICATION_NAME, object: nil, userInfo: ["products": productIds])
The notification has an object type of Any?.
When you're poing it in the console, you're asking it to print its description, which Any can do.
When you're asking it to subscript, Any can't do that, because subscripting is not defined on that type. You need to cast it to the expected type:
po (notification.object as? [String])?[0]
In general, it's best to nail down the type of any Any as soon as you can. Think of Any as a box used to send things through the post. The first thing you do is open it and find out what's inside.

get mediaSessionID for the current media playing on chrome cast in Swift on iOS

I'm referring to https://developers.google.com/cast/docs/reference/ios/interface_g_c_k_media_status.html#a45e3eb39e674f5d0dbfd78deef77a1e6
that helps me with the api, but the initializer for the GCKMediaStatus class says:
- (instancetype) initWithSessionID: (NSInteger) mediaSessionID
mediaInformation: (GCKMediaInformation *) mediaInformation
note: this is in Objective-c syntax but Swift works just the same except in Swift language...
Nonetheless I can't seem to figure out how to retrieve the mediaSessionID to be able to initialize an instance of this class to a new variable.
I'm trying to do the following to get me eventually to the method within this class called streamPosition which would go like this:
var mediaStatus = GCKMediaStatus(sessionID: Int, mediaInformation: GCKMediaInformation!)
var currentStreamPosition = mediaStatus.streamPosition()
where Int would be the mediaSessionID NOT the sessionID of the chrome cast (read the additional section below!!) and GCKMediaInformation! would be an instance of the GCKMediaInformation class. (I think) correct me if I'm wrong on either of those parameters.
Then I could use this data. But when I do this the currentStreamPosition I suppose defaults to 0 and thats what I get when I print to the currentStreamPosition variable.
Note: I've already connected to the current playing media and I am able to pause, play, and seek to an arbitrary number within the stream. This all works. So I now I'm connected and everything else works.
use case: I want to be able skip ahead 15 seconds or rewind 15 seconds etc. with the use of this method, but I haven't found anything to help.
also - don't get sessionID confused with mediaSessionID!! I CAN get the sessionID successfully and print it out. My issue is with the mediaSessionID.
additional info: the autocomplete is Xcode says this is the parameters labeled names:
GCKMediaStatus(sessionID: Int, mediaInformation: GCKMediaInformation!)
note the first parameter says sessionID and it is of type int. But on https://developers.google.com/cast/docs/ios_sender if you notice sessionID is of type String! (an optional String).
I think this label was mis-named in Xcode for the autocomplete. I think it should be named mediaSessionID and NOT sessionID since this is what the documentation shows on the first link I provided.
Any help would be much appreciated.
Thanks!
To get the stream position, use the method approximateStreamPosition on GCKMediaControlChannel.

Casting generic array in swift cause fatal error

I have a class which acts as a BLL, wrapping a service protocol. The service protocol provides a list of SerializableObjectProtocol objects. For instance, I have User, which implements SerializedObjectProtocol.
The following function casts a SerializedObjectProtol array into a User
public func Get() -> [T]
{
let result = self._service.Get()
return result as! [T]
}
As a result, I am getting the following error:
array element cannot be bridged to Objective-C
I am aware that the code is error prone, because if the object is not T, down casting cannot happen. As a result, here is what I can verify:
T in constrained to implement SerializedObjectProtol i.e.
class DataLayer<T:SerializableObjectProtocol>
T is type User. The result is an array of user. i.e. [User]
I can get around this issue, but I have to manually cast each item. As a result, this works perfectly fine:
var returnArray = [T]()
for item in result
{
returnArray.append(item as! T)
}
return returnArray;
I have just picked up Swift for a project so I have limited experience with it. As a result, I have gone out to see if what I am trying is possible (casting array [S] to [T]). It seems that it is possible if the array is [Any].
Is this a valid operation in Swift? Or is casting this way not possible.
Generally it is not possible to cast directly between an array of Any to the type it contains, because Any has a completely different representation in memory: sizeof(Any) isn't equal to sizeof(User)! An array of 10 Anys might have a length of 320 bytes, but 10 Users only need 80 bytes, the same applies to any protocol. Conclusion: You need to cast every single item.
Maybe do it like this:
return results.map{ $0 as! User }
or if you're not sure whether every item is a User, you can only return the Users like this:
return results.flatMap{ $0 as? User }
If you're still having problems, please post some minimal code that still produces the error, it's really hard to understand what your code looks like without the actual code

iOS/core-data: What is best way to check if there is a value for an attribute in core data?

There are a lot of variants of this question asked but none seem to quite get what I need.
I have an object, contact, which is in a core data entity contacts. I want to display as much of the address as is present so if there is no zip for example for example, I will leave that out.
I have tried variants of the following without any success:
if (self.contact.state && !self.contact.zip) {
NSString *location = contact.state;
}
and also
self.contactZip.text = self.contact.zip;
if (length(self.contactZip.text)<1) {
NSString *location = contact.state;
}
Can anyone suggest right way to do this?
Thx.
The way to check for the presence of a value with Core Data (as with any Objective-C property) is to check and see if the value is nil:
if (self.contact.zip == nil) {
...
}
Although the ! syntax is common, it's better to write the code to specifically check for nil [Partly because it makes your code clearer about what it's doing. Partly because ! is a boolean operator that only happens to work when checking for nil because of implementation details of the language.].
If the property is a string and what you actually want to know is whether it has non-zero length, check both (because a zero-length string is not the same as a nil value). In Objective-C you can take advantage of the language's treatment of nil method calls and do
if ([self.contact.zip length] == 0) {
...
}
Calling length on a nil argument will return zero, so in ObjC this ends up checking both for nil and for zero length at the same time.

If Statement Failing sometimes with id BoolValue Comparison?

I am pulling data from the web that is formatted in JSON and when I parse the data using "ValueForKeyPath" it stores the string value as an id object.
So I store the data into a NSMutableArray
In the debugger window it shows all the elements added as (id) null.
I have an if statement
if ([[self.activeCategories objectAtIndex:selected] boolValue] == true)
Sometimes I would say 20% of the time it fails the if statement when it should not.
I was wondering if it was because the self.activeCategories is storing id types. Do I need to do [NSString stringWithFormat#"%#", x] to all the objects inside the array? It seems like when I just straight cast it by using (NSString *) it is still type id in the debugger.
It's a very strange error to me... as the error is not consistently reproducible.
Try it like that:
if ([[self.activeCategories objectAtIndex:selected] boolValue])
According to that article a BOOL may hold values other than 0 and 1 which may fail the comparison.

Resources