‘CGFloat’ is not convertible to ‘UInt8' and other CGFloat issues with Swift and Xcode 6 beta 4
Asked Answered
M

4

13

In case this illuminates the problem, here's the original Objective-C code.

int x = (arc4random()%(int)(self.gameView.bounds.size.width*5)) - (int)self.gameView.bounds.size.width*2;
int y = self.gameView.bounds.size.height;
drop.center = CGPointMake(x, -y);

I started out with this code. Lines 2 and 3 are fine, I'm presenting them for clarity later.

let x = CGFloat(arc4random_uniform(UInt32(self.gameView.bounds.size.width * 5))) - self.gameView.bounds.size.width * 2
let y = self.gameView.bounds.size.height
dropView.center = CGPointMake(x, -y)

In Xcode 6 beta 3, it was necessary to cast the arc4random_uniform UInt32 result to CGFloat in order for the minus and multiplication to work. This doesn't work anymore and the compiler shows an error:

‘CGFloat’ is not convertible to ‘UInt8’

The release notes state:

"CGFloat is now a distinct floating-point type that wraps either a Float on 32-bit architectures or a Double on 64-bit architectures. It provide all of the same comparison and arithmetic operations of Float and Double and may be created using numeric literals. Using CGFloat insulates your code from situations where your code would be !fine for 32-bit but fail when building for 64-bit or vice versa. (17224725)"

Am I just doing something wrong with types? I don't even know how to describe this problem better to submit a bug report to Apple for beta 4. Pretty much every single Swift project I have that does any kind of point or rect manipulation got hit by this issue, so I'm looking for some sanity.

Mowbray answered 21/7, 2014 at 19:33 Comment(2)
As for the problem report, I think it's simply that UInt32 cannot be converted to CGFloat and vice versa.Krasnoyarsk
Posted as bug report 17758869Mowbray
K
9

Since Swift doesn't have implicit type conversions, you must specify all the type conversions that take place. What makes this case particularly tedious, is that currently Swift seems to lack direct conversions between CGFloat and types such as UInt32, and you must go through an intermediate type as you've discovered.

In the end, two double conversions are needed for the arc4random_uniform:

let bounds = CGRectMake(0.0, 0.0, 500.0, 500.0)
var x = CGFloat(UInt(arc4random_uniform(UInt32(UInt(bounds.size.width) * 5))))
x -= bounds.size.width * 2
let center = CGPointMake(x, -bounds.size.height)
Krasnoyarsk answered 21/7, 2014 at 21:39 Comment(2)
In fact, the conversion problem with CGFloat seems to be only one way, you can cast the CGFloat value to UInt32 directly: CGFloat(UInt(arc4random_uniform(UInt32(bounds.size.width * 5))))Reactionary
I'm seeing an error with your suggestion Rob, are you using beta 4? I had to use Uint as Arkku suggests or Int. beta 3 worked differently.Mowbray
O
2

Had the same problem ... try wrapping

arc4random_uniform 

with

Int()

like

Int(arc4random_uniform)

this worked for me ... don't know why Swift/Xcode hast problems converting unsigned INT's

Orangery answered 21/7, 2014 at 20:58 Comment(1)
You should really wrap it in Uint as the answer above does. Wrapping it as an Int will work, but is not recommended (especially if working with large numbers) because it could cause a loss of precision.Walsingham
M
0

@Arkku provided the correct solution, so the one-liner for x is...

let x = CGFloat(UInt(arc4random_uniform(UInt32(UInt(self.gameView.bounds.size.width) * 5)))) - self.gameView.bounds.size.width * 2

As of Xcode 6 beta 5, you can still use an intermediate conversion if you want and your code will continue to work. However, it is no longer necessary, so the following now works as expected.

let x = CGFloat(arc4random_uniform(UInt32(self.gameView.bounds.size.width * 5))) - self.gameView.bounds.size.width * 2

Since the original question is only relevant to Xcode 6 beta 4, what is the proper way to handle the question? Is there a historical mark? Should it be deleted?

Mowbray answered 21/7, 2014 at 19:33 Comment(0)
M
0

TL;DR simple shortcuts cause HCF: Halt and Catch Fire bugs

Note that there are some obvious work legal work arounds like implementing conversion to and from CGFloat:

Totally legal, but don't do this:

extension Float {
    func __conversion() -> CGFloat { return CGFloat(self) }
}

extension CGFloat {
    func __conversion() -> Float { return Float(self) }
    func __conversion() -> Double { return Double(self) }
}

extension Double {
    func __conversion() -> CGFloat { return CGFloat(self) }
}

I did not notice when typing, but later my machine kept overheating and hanging and SourceKit went to 300-500%, and the swift proceess + kernel_task took up 10+ gigs of RAM, consuming all that was left of my 16 gigs. It took a long time to trace it back to this - it wasn't swift.

Meletius answered 23/7, 2014 at 3:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.