NEW: Master Swift design patterns with my latest book! >>

< Previous: Setting up   Next: Generating random numbers with GameplayKit: GKRandomSource >

Generating random numbers without GameplayKit

There were lots of ways you can generate random numbers before GameplayKit came along, but none were both easy and good. The most popular is called arc4random(), which is able to generate large, seemingly random numbers with a single function call:

print(arc4random())
print(arc4random())
print(arc4random())
print(arc4random())

The arc4random() function generates numbers between 0 and 4,294,967,295, giving a range of 2 to the power of 32 - 1, i.e., a lot. But if you wanted to generate a random number within a specific range – say up to 5 – there were two ways of doing it: the way most people use, and The Proper Way. Let's look at them both, because you'll encounter them both in real code.

First, the widely used but problematic way of generating random numbers in a range:

print(arc4random() % 6)

That uses modulus to ensure that the result from arc4random() falls within a specific range. We already covered modulus in project 8 so skip back there if you need a refresher. Note that we need to specify 6 because the values range from 0 to 5 inclusive.

This method is very common, but also problematic because it produces something called modulo bias, which is a small but not insignificant problem that causes some numbers to be generated more frequently than others. You might know it as the Pigeonhole Principle if you prefer slightly catchier names!

So, here’s The Proper Way of generating random numbers in a range:

print(arc4random_uniform(6))

Yes, the ARC4 family of functions comes with a built-in way of generating random numbers in a range. No, it's not new. No, I don't know why it's not used by everyone – the world's a funny place, huh?

Anyway, using arc4random_uniform() we can generate a range of numbers that don't have a modulo bias, don't require seeding, and are suitably random for all but cryptographic purposes.

But it's not perfect, because its range is 0 up to the maximum you specify – what if you want a number between 10 and 20, or 100 and 500? Then you need to write something thoroughly ugly indeed:

func RandomInt(min: Int, max: Int) -> Int {
    if max < min { return min }
    return Int(arc4random_uniform(UInt32((max - min) + 1))) + min
}

That figures out the difference between the high and low ends of your range, uses that to calculate a random number, then re-adds the low end to get the full range. Because arc4random_uniform() works only with non-negative integers (UInt32) it has to do some typecasting to make the process seamless, and all those extra parentheses probably give you a headache.

Does it work? Yes, absolutely. Could you remember it if you closed this window now? No chance.

But I have some good news for you: all this complexity gets wiped away if you use GameplayKit. Not only does it do everything above better, but it has ridiculously simple syntax that you're going to get hooked on – there’s a reason I introduced it to you so early in this series!

Before I continue, it's worth making it doubly clear that GameplayKit is available only on Apple’s platforms, so if you’re using open source Swift on Linux then you’ll need to stick with the other options shown above.

Master iOS 11 now!

My book Practical iOS 11 gives you seven complete coding projects that teach all the major new features in iOS 11 in a smart, practical way.

< Previous: Setting up   Next: Generating random numbers with GameplayKit: GKRandomSource >
Click here to visit the Hacking with Swift store >>