58

I have this expression which returns a UInt32:

let randomLetterNumber = arc4random()%26

I want to be able to use the number in this if statement:

if letters.count > randomLetterNumber{
    var randomLetter = letters[randomLetterNumber]
}

This issue is that the console is giving me this

Playground execution failed: error: <REPL>:11:18: error: could not find an overload for '>' that accepts the supplied arguments
if letters.count > randomLetterNumber{
   ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~

The problem is that UInt32 cannot be compared to an Int. I want to cast randomLetterNumber to an Int. I have tried:

let randomLetterUNumber : Int = arc4random()%26
let randomLetterUNumber = arc4random()%26 as Int

These both cause could not find an overload for '%' that accepts the supplied arguments.

How can I cast the value or use it in the if statement?

67cherries
  • 6,931
  • 7
  • 35
  • 51

4 Answers4

87

Int(arc4random_uniform(26)) does two things, one it eliminates the negative results from your current method and second should correctly creat an Int from the result.

David Berry
  • 40,941
  • 12
  • 84
  • 95
  • 2
    Thanks for that, the Int() initializer seems to do the trick. – 67cherries Jun 10 '14 at 15:19
  • 3
    You can read more about numeric type conversion in **[Apple's Swift docs](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_420)**. – Nate Cook Jun 10 '14 at 15:21
  • 7
    Thanks. I had a similar problem with arc4random_uniform(someArray.count) casting fixes the problem arc4random_uniform(UInt32(someArray.count)) – nacross Jun 12 '14 at 12:46
  • I had both problems: probability = Int(arc4random_uniform(UInt32(total))) … the main problem is because of the headers the type-ahead doesn't have info on this method and doesn't provide the needed metadata (which it would then offer as suggestions to fix the problem) – bshirley Jan 07 '16 at 17:56
25

More simple than this, impossible:

Int(myUInteger)
Josh
  • 6,251
  • 2
  • 46
  • 73
11

Just create a new int with it

let newRandom: Int = Int(randomLetterNumber)
if letters.count > newRandom {
    var randomLetter = letters[newRandom]
}

or if you never care about the UInt32 you can just create an Int immediately:

let randomLetterNumber = Int(arc4random() % 26)
Firo
  • 15,448
  • 3
  • 54
  • 74
  • Note that this will throw an exception half the time due to overflow checking, use the answer I gave to avoid that. – David Berry Jun 10 '14 at 15:17
  • @David, how so? Not disagreeing, just want to understand what you mean. – Firo Jun 10 '14 at 15:19
  • 1
    Actually it won't since you're doing the casting after the modulo, so you can guarantee it's always in bounds. `Int(arc4random())` will crash 50% of the time it's executed on a 32-bit platform because a UInt32 won't fit in an Int32. Just seen too many "arc4random is bugged and crashes" questions with swift. In any case arc4random_uniform will give a more uniform distribution. – David Berry Jun 10 '14 at 17:41
  • 1
    Modifying/bounding the output of a random number distribution with modulo or division operations is poor form: it ruins the distribution properties that the functions guarantee. Instead, use `arc4random_uniform(26)` to let the function uphold a uniform distribution across the range you specify. – cbowns Sep 22 '15 at 05:24
5

You can do

let u: UInt32 = 0x1234abcd
let s: Int32 = Int32(bitPattern: u)
applequist
  • 304
  • 3
  • 9