"'CGFloat' is not convertible to 'UInt8'" - CGFloat wrapping issue - ios

label.position = CGPointMake(self.size.width*0.125, self.size.height-CGFloat(0.15)*self.size.height*_activeEnemiesArray.count)
I get an error pointing to self.size.width that says
'CGFloat' is not convertible to 'Double'.
This makes sense, since a CGFloat value and a Double value cannot be multiplied, but then when I convert the 0.125 to CGFloat:
label.position = CGPointMake(self.size.width*CGFloat(0.125), self.size.height-0.15*self.size.height*_activeEnemiesArray.count)
I get an error pointing to self.size.width that says
'CGFloat' is not convertible to 'UInt8'
This does not make any sense. Has anyone else been experiencing this and what could be the cause?

Xcode is leading you astray -- literals shouldn't really ever cause problems, as they'll get converted into Double or CGFloat as needed once everything else is the same type. Instead, what's going on is that you have an Int at the very end of your line:
... * self.size.height * _activeEnemiesArray.count)
That count property needs to be converted to CGFloat so it can be used with the rest:
... * self.size.height * CGFloat(_activeEnemiesArray.count))

just try
self.frame.size.width

Related

Why does the compiler claim CGRect has no width member?

Note that I'm not trying to set the value in a CGRect. I'm mystified as to why the compiler is issuing this claim:
let widthFactor = 0.8
let oldWidth = wholeFrameView.frame.width
let newWidth = wholeFrameView.frame.width * widthFactor // Value of type '(CGRect) -> CGRect' has no member 'width'
let newWidth2 = wholeFrameView.frame.width * 0.8 // This is fine.
Width is a CGFloat where your multiplier is a Double. Explicitly declare the type of your multiplier:
let widthFactor: CGFloat = 0.8
All the dimensions of a CGRect are of type CGFloat, not Double, and because Swift is especially strict about types, you can't multiply a CGFloat by a Double.
The interesting thing though, is that both CGFloat and Double implement ExpressibleByFloatLiteral. This means that 0.8, a "float literal", can be interpreted as either a Double or a CGFloat. Without context, it's always a Double, because of how the compiler is designed. Note that this only applies to float literals like 3.14, 3e8 etc, and not to identifiers of variables.
So the expression wholeFrameView.frame.width * 0.8 is valid because the compiler sees that width is a CGFloat, so it treats 0.8 as a CGFloat as well. No problems.
On the other hand, when you declare the variable widthFactor, it is automatically given the type Double, because there aren't any more context on that line to suggest to the compiler that you want it to be any other type.
This can be fixed by directly telling the compiler that you want widthFactor to be a CGFloat:
let widthFactor: CGFloat = 0.8
Because, as others have noted, you can't multiply a Double and a CGFloat, the compiler doesn't know what you're intending.
So, instead of giving you an error about the frame property, which you currently think it's doing, it's actually making its best guess*, and giving you an error related to the frame method. No method method has a width property, so what it tells you is true.
*Of course, its best guess is not good enough, hence a human being coming here to ask a question about it. So please file a bug!
Stepping onto my soapbox: This confusion would be avoided if Apple hadn't named the method the thing it returns. The convention to prefix all such methods with get solves the problem. Some convention is important in any language with first-class functions, to disambiguate between properties and methods.
wholeFrameView.frame has no member width. Also, you need widthFactor to be of type CGFloat. Try:
let newWidth = wholeFrameView.frame.size.width * CGFloat(widthFactor)

How can I convert CLLocationManager.magneticHeading to radians?

I am trying to covert the number of magneticHeading that I see, from 0 to 360, into radians so I can use CGPoint. However this code throws an error.
//Code to move on the X plane
let heading = self!.locManager.heading
let MagHeading = (heading?.magneticHeading)! * M_PI/180 //error
How can I covert this CLLocation value I get from the heading into a float so I can turn it into radians?
The error is that heading is nil. Yet without the conversion it still produces values
Actual problem and your question are absolutely different. You need to handle optional variable there... but you mentioned conversion between double/float to radian
try this... at least your error will be gone.
if let heading = self.locManager.heading {
let MagHeading = (heading.magneticHeading) * M_PI/180
print("MagHeading - \(MagHeading)")
} else {
print("heading is nil")
}

Swift error: "double is not convertible to UInt8"

var dvalue:Double = 1.03
var stok1 = SKSpriteNode(imageNamed: "stok")
stok1.zRotation = dvalue * stok1.zRotation
This piece of code gives this error in the last line:
"Double is not convertible to UInt8"
How to fix this?
zRotation is a CGFloat.
Your dValue is a Double.
They are not compatible. To multiply them, they must be same type: either both CGFloat or both Double. In this case, clearly CGFloat is desirable, since we will be assigning the result to a CGFloat.
Declare your dValue as a CGFloat, therefore, and all will be will.

What am I doing wrong with Swift and basic geometry

When I use the hard coded data for diameter and height Swift runs simulator fine, but when I try and use text values in place using TextField.text.toInt() then I keep getting very annoying error message of:-
cannot invoke \ with an argument list of type $st15
Just where am I going wrong. I am new to Swift and have only used AppInventor before to create an app with a few thousand downloads. I am a enthusiastic but probably slow learner, but I will get there if someone would be so kind to help me out a little. Note: Formula is simply PIr2 x h to give cylinder volume. I want to use diameter which explains why I am halving each time.
let PI = 3.142
var bodyDiameter = bodyDiameterTextField.text.toInt() // 3.0
var bodyHeight = bodyHeightTextField.text.toInt() // 10.0
var cylinderVolume: Double
var cylinderVolume = (PI * (bodyDiameter / 2.0) * (bodyDiameter / 2.0)) * bodyHeight
println("cylinderVolume")
cylinderVolumeLabel.text = "(cylinderVolume)"
Here follows same code with hard coded values for Bodydiameter and Bodyheight. It all works great in the playground and the simulator. I guess its got something to do with Integers and Floats, but I'm probably way out.
let PI = 3.142
var bodyDiameter = 3.0
var bodyHeight = 10.0
var cylinderVolume = (PI * (bodyDiameter / 2.0) * (bodyDiameter / 2.0)) * bodyHeight
println("cylinderVolume")
cylinderVolumeLabel.text = "(cylinderVolume)"
Your code has several errors.
First, and not really an error, there's already a built-in constant for π, named M_PI. Use that instead of defining your own PI constant.
Next, String.toInt() returns an Int?. The question mark means the return type is really Optional<Int>. This is a container that is either empty (nil), or contains an Int. If you want to use the Int value, you need to unwrap it. You might want to check that the Optional isn't nil first, though.
Next, assuming you unwrap the Int, you can't perform arithmetic on mixed Int and Double values in Swift. You have to convert to all Int or all Double. You probably want to use all Double. In fact, you probably don't want to convert from Int to Double at all. You probably want to get a Double from the text field in the first place. There's no toDouble on String in Swift, but there are some other ways to do it.
Finally, you need to say \(cylinderVolume) to interpolate the value into the string. Your code omits the \.
Try this:
var bodyDiameter = (bodyDiameterTextField.text as NSString).doubleValue
var bodyHeight = (bodyHeightTextField.text as NSString).doubleValue
var cylinderVolume = (M_PI * (bodyDiameter / 2.0) * (bodyDiameter / 2.0)) * bodyHeight
println("cylinderVolume: \(cylinderVolume)")
cylinderVolumeLabel.text = "(cylinderVolume)"
If you want to convert the strings to Doubles in a localization-friendly way, or detect when the strings aren't valid Doubles, look up NSNumberFormatter.

Bug in fminf and fmaxf on iOS 64bit processors

I came across a bug with the 64bit processors that I wanted to share.
CGFloat test1 = 0.58;
CGFloat test2 = 0.40;
CGFloat value;
value = fmaxf( test1, test2 );
The result would be:
value = 0.5799999833106995
This obviously is a rounding issue, but if you needed to check to see which value was picked you would get an erroneous result.
if( test1 == value ){
// do something
}
however if you use either MIN( A, B ) or MAX( A, B ) it would work as expected.
I thought this is was worth sharing
Thanks
This has nothing to do with a bug in fminf or fmaxf. There is a bug in your code.
On 64-bit systems, CGFloat is typedef'd to double, but you're using the fmaxf function, which operates on float (not double), which causes its arguments to be rounded to single precision, thus changing the value. Don't do that.
On 32-bit systems, this doesn't happen because CGFloat is typedef'd to float, matching the argument and return type of fmaxf; no rounding occurs.
Instead, either include <tgmath.h> and use fmax without the f suffix, or use float instead of CGFloat.

Resources