Learn everything what you'll ever need to generate random values in Swift using the latest methods and covering some old techniques.
How to generate random numbers using Swift?
Fortunately random number generation has been unified since Swift 4.2. This means that you don't have to mess around with imported C APIs anymore, you can simply generate random values by using native Swift methods on all platforms! 😍
As you can see generating a dice roll is now super easy, thanks to the cryptographically secure randomizer that’s built into the Swift language. The new random generator API also better at distributing the numbers. The old arc4random function had some issues, because the generated values were not uniformly distributed for example in between 1 and 6 due to the modulo bias side effect. 🎲
Random Number Generator (RNG)
These examples above are implicitly using the default random number generator (SystemRandomNumberGenerator) provided by the Swift standard library. There is a second parameter for every method, so you can use a different RNG if you want. You can also implement your own RNG or extend the built-in generator, if you'd like to alter the behavior of distribution (or just give it some more "entropy"! 🤪).
Collections, random elements, shuffle
The new random API introduced some nice extensions for collection types. Picking a random element and mixing up the order of elements inside a collection is now ridiculously easy and performant (with custom RNG support as well). 😉
Randomizing custom types
You can implement random functions on your custom types as well. There are two simple things that you should keep in mind in order to follow the Swift standard library pattern:
- provide a static method that has a (inout) parameter for the custom RNG
- make a random() method that uses the
Generating random values using GameplayKit
The GameplayKit provides lots of things to help you dealing with random number generation. Various random sources and distributions are available inside the framework, let's have a quick look at them.
Random sources in GameplayKit
GameplayKit has three random source algorithms implemented, the reason behind it is that random number generation is hard, but usually you're going to go with arc4 random source. You should note that Apple recommends resetting the first 769 values (just round it up to 1024 to make it look good) before you're using it for something important, otherwise it will generate sequences that can be guessed. 🔑
GKARC4RandomSource - ok performance and randomness
GKLinearCongruentialRandomSource - fast, less random
GKMersenneTwisterRandomSource - good randomness, but slow
You can simply generate a random number from int min to int max by using the
nextInt() method on any of the sources mentioned above or from 0 to upper bound by using the
Random distribution algorithms
GKRandomDistribution - A generator for random numbers that fall within a specific range and that exhibit a specific distribution over multiple samplings.
Basically we can say that this implementation is trying to provide randomly distributed values for us. It's the default value for shared random source. 🤨
GKGaussianDistribution - A generator for random numbers that follow a Gaussian distribution (also known as a normal distribution) across multiple samplings.
The gaussian distribution is a shaped random number generator, so it's more likely that the numbers near the middle are more frequent. In other words elements in the middle are going to occure significantly more, so if you are going to simulate dice rolling, 3 is going to more likely happen than 1 or 6. Feels like the real world, huh? 😅
GKShuffledDistribution - A generator for random numbers that are uniformly distributed across many samplings, but where short sequences of similar values are unlikely.
A fair random number generator or shuffled distribution is one that generates each of its possible values in equal amounts evenly distributed. If we keep the dice rolling example with 6 rolls, you might get 6, 2, 1, 3, 4, 5 but you would never get 6 6 6 1 2 6.
How to shuffle arrays using GameplayKit?
You can use the
arrayByShufflingObjects(in:) method to mix up elements inside an array. Also you can use a seed value in order to shuffle elements identically. It's going to be a random order, but it can be predicted. This comes handy if you need to sync two random arrays between multiple devices. 📱
GameplayKit best practice to generate random values
There is also a shared random source that you can use to generate random numbers. This is ideal if you don't want to mess around with distributions or sources. This shared random object uses arc4 as a source and random distribution. 😉
Please note that none of these random number generation solutions provided by the GameplayKit framework are recommended for cryptography purposes! ⚠️⚠️⚠️
Pre-Swift 4.2 random generation methods
This C function was very common to generate a dice roll, but it's also dangerous, because it can lead to a modulo bias (or pigenhole principle), that means some numbers are generated more frequently than others. Please don't use it. 😅
This method will return a uniformly distributed random numbers. It was the best / recommended way of generating random numbers before Swift 4.2, because it avoids the modulo bias problem, if the upper bound is not a power of two.
The drand48 function returns a random floating point number between of 0 and 1. It was really useful for generating color values for random UIColor objects. One minor side note that it generates a pseudo-random number sequence, and you have to provide a seed value by using
srand48 and usually a time parameter. 🤷♂️
Linux support, glibc and the rand method
I was using this snippet below in order to generate random numbers on both appleOS and linux platform. I know it's not perfect, but it did the job for me. 🤐
Now that we have Swift 4.2 just around the corner I'd like to encourage everyone to adapt the new random number generation API methods. I'm really glad that Apple and the community tackled down this issue so well, the results are amazing! 👏👏👏