I’m trying to get GPS speed in Swift. I've set everything up and am now trying to do some calculations. I want to convert the MS "string" to KMH. So I'm trying to convert the type to long, but I can’t get it to work.
I have tried this:
var ms: long?
ms = LocationManager.location.speed
But I got "CLLocationspeed is not convertible to long”
I’m new to iOS programming and Swift so I don't know how to fix this.
You should really start by reading the Swift Book, however:
long isn’t a standard type in Swift (not sure where you’ve managed to find one :). An appropriate integer type to use would be Int (unless exact size matters to you – but it probably doesn’t). But CLLocationSpeed in CoreLocation is a typealias for Double and you should probably stick with that for speed calculations.
In Swift, most conversions between types do not happen implicitly. If you really wanted a Double to become an Int, you need to explicitly convert it i.e. let ms = Int(LocationManager.location.speed).
This feels like a pain when you are coming from C-like languages. But there are good reasons behind it. For example, what should happen to the fractional part of the floating-point number when you assign it to an integer type? Might you have forgotten your function is returning a floating point number and have accidentally introduced a truncation bug?
To make up for this, Swift also has type inference. So unless you want to explicitly control the types, you don’t even have to give them:
// type of ms is automatically inferred to be CLLocationSpeed (alias for Double)
let ms = LocationManager.location.speed
// 3.6 floating-point literal is automatically converted to appropriate type
// type and kph is automatically a Double
let kph = ms * 3.6
Most of the time you don’t need to give a type, just leave it to be inferred it from the context.
Swift does not have a long datatype.
CLLocationSpeed is just a typealias for Double in Swift
So if you want to convert it into Double, do this
var ms = Double(LocationManager.location.speed)
The Swift compiler will automatically figure out the type for the variable
and then you can substitute Double(value) with Int, Float or any other Swift datatype
to typecast the value.
Related
This question relates to F# units of measure.
Should I enforce a type for a unit I am using.
For example should I enforce that seconds are always a float?
let asSeconds time = float(time)*1.0<second>
This seems a tad bit restrictive, since NASA may want to use decimal. On the other hand I don't know how to convert a generic a' into a unit a'<seconds>. The issue I am facing is that some application level functions do NOT use units, but some library stuff DO use units.
P.S. This is lightly related to my previous question
should I enforce that seconds are always a float?
I don't think you could really enforce this, since units of measure are not inherently tied to a specific numeric type. For example, both of the following would be legal:
let a = 1<second> // a : int<second>
let b = 1.0<second> // b : float<second>
I don't know how to convert a generic 'a into a unit 'a<seconds>.
This is an interesting question, but I don't think it's possible to write a generic version of asSeconds, because units of measure can only be applied to literals, and literals are never generic in F#. So you can't write time<second> or time * GenericOne<second>.
Bottom line, when converting from a dimensionless value to a dimensioned value you have to pick a specific numeric type, like float. But this doesn't mean that you can force all values of that UOM to have that numeric type.
Let's say I have a function foo which takes two arguments:
actual fun foo(list1: List<Long>, list2: List<Double>) {
...
}
According to the https://kotlinlang.org/docs/tutorials/native/apple-framework.html Kotlin's Long type is mapped to KotlinLong and Kotlin's Double is mapped to KotlinDouble. Now I would like to call this function from my iOS App. Let's say I have two arrays:
let list1Numbers = [1000.43, 564121.34, 5617172172.234, 100.7]
let list2Numbers = [2.1, 3.2, 1.7]
For the list2 I could do something like:
let list2NumbersKotlin = list2Numbers.map({KotlinDouble.init(double: $0)})
which is not very convenient but will work. The list1 is a bit more problematic. Since there is no Long in Swift, I do something like
let list1NumbersKotlin = list1Numbers.map({KotlinLong.init(longLong: Int64($0))})
Questions:
Is there a better way to do it ?
What is a typical approach to deal with such types mapping when using Kotlin as an iOS Framework ? Unfortunately I couldn't find any examples on the Internet.
Should certain types such as Long be completely avoided if I want to use Kotlin as iOS Framework ?
Also, regarding mapping in general: since the Kotlin function
fun testDouble(testVal: Double) {}
allows me to pass in Swift the Double directly:
HelloKt.testDouble(testVal: Double)
then why does the function
fun testList(testList: List<Double>) {}
not allow me to enter Double array but requires a KotlinDouble array ?
HelloKt.testList(testList: [KotlinDouble]){}
Passing a [Double] gives error:
Cannot convert value of type '[Double]' to expected argument type
'[KotlinDouble]'
There are multiple ways.
You are talking about collections of data that are on the line between primitive types and objects, which tends to be a special case in Kotlin anyway.
Speaking to that, in Kotlin, you might want a LongArray and a DoubleArray rather than List<Long> and List<Double>. Coming from Swift, you'll be forced to explicitly box them. Kotlin will handle that for you when you're writing Kotlin code, but they're still getting boxed under the hood.
So, summary, either what you've done above, or take LongArray and DoubleArray as args rather than lists, and do a different translation. Either way, you will need to move the data into something Koltin compatible.
Obviously, if you put that in a helper function, ugly as it perhaps may be, you only need to do it once.
Either your method or what I described.
Long isn't problematic. There is a "long" in Swift, it's Int64. Having to wrap values like that isn't fun, but Kotlin and Swift are different languages, and there are compromises. If you use Int in Kotlin instead of Long, you'll need to wrap a Swift Int with Int32. A Kotlin Int is, in that sense, "problematic" in the same way. You need to specify which precision int you're using.
In Kotlin, List<Long> is a list of Long objects, while just a Long is a primitive value. Kotlin hides the boxing of those values, but they are boxed. The Swift/Kotlin interface is forcing you to be more explicit. If you want primitive values, use the ___Array forms mentioned above.
I need to assign return value of a fetch:
try! c.fetch(fr)
to a to-many relationship (itemsWithoutRatingOfLoggedInUser):
Utility.app(c: c).itemsWithoutRatingOfLoggedInUser = try! c.fetch(fr2)
And got following error. What can I do? I tried to cast with as! operator, did not help.
Casting (with as) is for cases where a value of one type can be interpreted as a value of some other, explicitly related type. This interpretation is defined in terms of language features: either type relationships (like inheritance or protocol conformance), or the handful of special cases where Swift can bridge Foundation or CF types to/from their Swift Standard Library equivalents.
When you cast, you're asking the Swift compiler/runtime to squint its eyes a little and pretend that one type is another. (Maybe even do a little twiddling behind the scenes so that pretending works.) Most often, casting happens when you have a value where you know more about its type than Swift (in the context of the function you're writing) does.
When you have types that aren't explicitly related though language features — that is, one isn't a subclass of the other, or one isn't a protocol adopted by the other, or they aren't one of the special sets of equivalent types from Foundation/CF that Swift knows how to bridge — you have to convert, not cast. (Swift also makes you convert instead of casting when types are semantically different enough that you need to think about the consequences of conversion, like when going between signed and unsigned integers.)
Array and NSOrderedSet are semantically different enough types that you have to convert, not cast.
Conversion between types requires that the type being converted to know about the type being converted from, so to perform a conversion you use an initializer of the target type.
let stuff = managedObjectContext.fetch(request)
let orderedSet = NSOrderedSet(array: stuff)
Note that NSOrderedSet is not a generic type in Swift 3, so even if you create it from a typed array ([MyObject]), the elements come out as Any. That's a use case for casting:
let item = orderedSet as! MyObject
I have been doing Swift programming for a few months now and I have always been curious about this...
Is there an advantage to telling the Swift compiler the type of an object in its declaration?
I.e.let image: UIImage = UIImage()
Compared to NOT telling the compiler and having it infer the type at runtime. I.e let image = UIImage()
I would think it would be more efficient to tell the compiler the object type instead of having it infer the type. I know this question appeals to Objective-C syntax as well, so I'll add that in the tags.
There’s zero runtime efficiency difference between the two. During compilation, Swift is inferring the type and writing it in for you. But once compiled, the two statements are identical.
It’s purely a question of readability and, occasionally, compiler efficiency.
Readability because in the statement let image: UIImage = UIImage(), the double appearance of UIImage is just clutter. And in cases of more complex types, it’s pretty much essential – no-one wants to write let keys: LazyForwardCollection<MapCollectionView<Dictionary<String, Int>, String>> = dict.keys when they can write let keys = dict.keys.
Compiler efficiency because occasionally you’ll find that a particularly ambiguous type (literals of literals are notorious for this) where lots of overloads need to be resolved can compile a lot faster if you explicitly name the type on the left-hand side. But this is just a question of how fast it compiles, not how fast it runs once it has compiled.
From Swift Documentation:
It is rare that you need to write type annotations in practice. If you provide an initial value for a constant or variable at the point that it is defined, Swift can almost always infer the type to be used for that constant or variable, as described in Type Safety and Type Inference
So It doesn't matter if you declare instance type or not.
If we define a unit of measure like:
[<Measure>] type s
and then an integer with a measure
let t = 1<s>
and then convert it to a float
let r = float t
we see that r = 1.0 without a measure type. This seems very odd, as all the measure information has been lost.
You can use LanguagePrimitives.FloatWithMeasure to convert back to a float with something like
let inline floatMeasure (arg:int<'t>) : (float<'t>) =
LanguagePrimitives.FloatWithMeasure (float arg)
which enforces the right types, but this doesn't feel like the right solution as the docs for units of measure (http://msdn.microsoft.com/en-us/library/dd233243.aspx) say
However, for writing interoperability layers, there are also some explicit functions that you can use to convert unitless values to values with units. These are in the Microsoft.FSharp.Core.LanguagePrimitives module. For example, to convert from a unitless float to a float, use FloatWithMeasure, as shown in the following code.
Which seems to suggest that the function should be avoided in F# code.
Is there a more idiomatic way to do this?
Here's working snippet that does exactly what you need although gives warning
stdin(9,48): warning FS0042: This construct is deprecated: it is only for use in the F# library)):
[<NoDynamicInvocation>]
let inline convert (t: int<'u>) : float<'u> = (# "" t : 'U #)
[<Measure>] type s
let t = 1<s>
let t1 = convert t // t1: float<s>
However, I wouldn't suggest this approach.
First of all, UoM are compile-time, while type conversion let r = float t is runtime. At the moment of invocation, int -> float has no idea of whether it is int<s> or int<something_else>. So it is simply unable to infer a proper float<'u> at runtime.
Another thought is that philosophy behind UoM is wider than it's described. It is like saying the compiler, "well, it is int, but please treat it as int<s>". The goal is avoiding occasional improper use (e.g., adding int<s> to int<hours>).
Sometimes it makes no sense of int -> float conversion: think of int<ticks>, there is no sense of float<ticks>.
Further reading, credits to #kvb for pointing on this article.
(Caveat: I've not used units much in anger.)
I think that the only negative for using e.g. FloatWithMeasure is the unit-casting aspect (unitless to unitful). I think this is conceptually orthogonal to the numeric-representation-casting aspect (e.g. int to float). However there is (I think) no library function to do numeric-representation-casting on unit-ful values. Perhaps this is reflective of the fact that most unitful values model real-world continuous values, as so discrete representations like int are typically not used for them (e.g. 1<s> feels wrong; surely you mean 1.0<s>).
So I think it's fine to 'cast representations' and then 'readjust units', but I wonder how you got the values with different representations in the first place, as it's often typical for those representations to be fixed for a domain (e.g. use float everywhere).
(In any case, I do like your floatMeasure function, which un-confounds the unit-aspect from the representation-aspect, so that if you do need to only change representation, you have a way to express it directly.)