Swift error: "double is not convertible to UInt8" - ios

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.

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)

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.

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

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

Set font size equal to an integer?

In Swift, I have a line that says var timerFontSize = 85. I want to have the line timerLabel.font = UIFont(name: "HelveticaNeue-Ultralight", size: timerFontSize), although that doesn't work. It only allows me to type in a number, not assign it to a variable. The reason I don't want to just type in a number is because I have a timer, where every second the font variable drops by 1.
How can I set the font size equal to an integer?
simply type cast the number to CGFloat
UIFont(name: "HelveticaNeue-Ultralight", size: CGFloat(timerFontSize))
Using this line:
var timerFontSize = 85
You're setting your variable implicitly to type Int, while the method for creating a font takes a CGFloat argument.
You could cast this variable as a CGFloat when you call the method, or you could explicitly create the variable as a CGFloat type:
var timerFontSize: CGFloat = 85
It's worth noting that
var timerFontSize = 85.0
Creates timerFontSize as a double, and
var timerFontSize = 85.0f
creates timerFontSize as a float.
The former will work for 64-bit devices where CGFloat ends up being a double, and the latter will work for 32-bit devices where CGFloat ends up being a float. But you don't want to use either of these options as it will crash on the other device.
CGFloat is a typedef for float/double depending on whether the device is 32 or 64 bit processor.

Objective-C Double, Long Calculation

I am trying to calculate a long value divided by an integer to give me what I would expect to be a double, although the result I am getting is 0. The code I am using...
double daysByYear = daysSinceBirthdayToService/365;
NSLog(#"%d", daysByYear);
In this code, daysSinceBirthdayToService variable is a Long Double which can be NSLogged using the following code (long)daysSinceBirthdayToService
It is declaired in the header file as a property of
#property (nonatomic) NSInteger daysSinceBirthdayToService;
Can anybody help me out with this, thanks!
The issue is that / between two longs will do an integral division.
To force a floating point division at least one of the operands needs to be cast to double.
e.g.
double daysByYear = daysSinceBirthdayToService/(double)365;
or if you have a literal make that a double by adding a decimal point
double daysByYear = daysSinceBirthdayToService/365.0;
double daysByYear = daysSinceBirthdayToService/365.0;
Can it be that %d outputs decimal number not a double?

Resources