How to generate a random number is a classic challenge in programming. When we were students, we might know there is no real randomness in the world built on the CPU clock, processes or threads. The randomness comes from given a seed and some magical algorithms. And all of them are pseudo-randomness.

In C, there is a great method to generate a random number, which is called arc4random. We can use this method in Swift as well. It returns a random int number. If we need the random number be restricted with in a range, we could do a mod (%) calculation. But there is a trap here:

This is wrong code

let diceFaceCount = 6
let randomRoll = Int(arc4random()) % diceFaceCount + 1
print(randomRoll)

In fact it runs well in iPhone 5s and later, but in iPhone 5 and earlier, sometimes the program will crash. The worst situation for a developer is this kind of RANDOMNESS. It you cannot regenerate a bug stable, it is hard to say what is wrong with your code.

Good news is this case is quite simple. Int in Swift is analogous to NSInteger, determined by the architecture of the CPU. On a 32-bit CPU (which happens to be the type of iPhone 5), Int means Int32 in fact, while on 64-bit CPU (iPhone 5s and later), it is Int64. The value of arc4random returning is not the same, and will be always the type of UInt32. As a result, half of the returned values will be overflow when doing Int conversion in Int(arc4random()), which cause the code crashed in a possibility of 50%.

Actually, we will use another version of arc4random method for safety:

func arc4random_uniform(_: UInt32) -> UInt32

This version accepts an UInt32 (n for example) as parameter, and normalize the result to a number between 0 and n - 1. If we can ensure the input parameter is less than Int, the conversion error could be avoided:

let diceFaceCount: UInt32 = 6
let randomRoll = Int(arc4random_uniform(diceFaceCount)) + 1
print(randomRoll)

We can set up a method with a Range type as input, and returning a random number for later use.

func randomInRange(range: Range<Int>) -> Int {
    let count = UInt32(range.endIndex - range.startIndex)
    return  Int(arc4random_uniform(count)) + range.startIndex
}

for _ in 0...100 {
    print(randomInRange(1...6))
}

Further more, we can even design a Randomable protocol to extend the random method from Int to other types - random string, random element in an array or something else. It is just an exercise for you.