1

Hello I have a problem with my Swift code.

In my application some SKLabelNodes are supposed to have their y coordinate set to

CGRectGetMaxY(self.frame) - (nodes[i].frame.size.height / 2 + 30) * (i + 4)

Where

var i:Int = 0

is a counter.

It works perfectly fine if instead of (i + 4) I just give it a literal value e.g. 5 or even (i == 0? 4 : 5) (just to see on two consecutive integers if the formula is correct itself).

But when I go with any variable or constant or expression containing one, it displays an error "CGFloat is not convertible to Int". It seems completely illogical, because 4 is an integer and so is i and even (i + 4), in which case changing 4 to i shouldn't change the whole expression's type.

Can anyone explain why do I get this error and how can I possibly solve it?

Thanks in advance.

Fiodor
  • 796
  • 2
  • 7
  • 18
  • possible duplicate of [Swift numerics and CGFloat (CGPoint, CGRect, etc.)](http://stackoverflow.com/questions/24108827/swift-numerics-and-cgfloat-cgpoint-cgrect-etc) – matt Dec 13 '14 at 17:48
  • 1
    It might also help to ask yourself what keeps you from finding out the answer to this question without wasting bandwidth by posting a new question of your own. This stuff is plastered all over the Internet in general and Stack Overflow in particular. Searching is basic programming skill these days. – matt Dec 13 '14 at 17:53
  • Yes, I agree. I jus missed the fact that literals are converted automatically and variables / constants are not. It also didn't help that "println(nodes[i].frame.size.height * i);" would only result in "Could not find member 'height'". So actually I didn't know what the problem even was. – Fiodor Dec 13 '14 at 18:05
  • 1
    "It also didn't help" Tell me about it! Actually, tell Apple about it. If you fail to coerce to the correct type explicitly, the compile error message you get will be _very_ mysterious and unrelated. You can spend hours tracking down this sort of thing. So whenever you run into a use case like this, file a bug with Apple asking for better compiler analysis and error messages. If you have time, that is. :) – matt Dec 13 '14 at 18:19

1 Answers1

2

You have already explained and solved the matter perfectly. It's simply a matter of you accepting your own excellent explanation:

It works perfectly fine if ... I just give it a literal value ... But when I go with any variable or constant or expression containing one, it displays an error "CGFloat is not convertible to Int".

Correct. Numeric literals can be automatically coerced to another type, such as CGFloat. But variables cannot; you must coerce them, explicitly. To do so, initialize a new number, of the correct type, based on the old number.

So, this works automagically:

let f1 : CGFloat = 1.0
let f2 = f1 + 1

But here, you have to coerce:

let f1 : CGFloat = 1.0
let f2 = 1
let f3 = f1 + CGFloat(f2)

It's a pain, but it keeps you honest, I guess. Personally I agree with your frustration, as my discussion here will show: Swift numerics and CGFloat (CGPoint, CGRect, etc.) It is hard to believe that a modern language is expected to work with such clumsy numeric handling, especially when we are forced against our will to bang into the Core Graphics CGFloat type so frequently in real-life Cocoa programming. But that, it seems, is the deal. I keep hoping that Swift will change in this regard, but it hasn't happened so far. And there is a legitimate counterargument that implicit coercion, which is what we were doing in Objective-C, is dangerous (and indeed, things like the coming of 64-bit have already exposed the danger).

Community
  • 1
  • 1
matt
  • 515,959
  • 87
  • 875
  • 1,141