Get hired as an iOS developer
Learn to build iOS 14 apps with Swift 5
Sign up for my iOS development course, and learn how to start your career as a professional iOS developer.
Let’s take a look at randomness and random numbers in Swift. Swift has a number of built in functions that help you generate random numbers, with a few caveats though!
But first… why would you need random numbers in Swift?
Let’s get started!
This article can be used with Swift 5, and prior versions. Simply skip to the appropriate chapter.
In Swift 4.2. and higher, the way you work with random numbers has changed. Instead of using the imported C function arc4random()
, you can now use Swift’s own native functions.
Let’s look at an example:
let number = Int.random(in: 0..<10)
The above example generates a random integer number between 0 and 10. The half-open range operator ..<
is used, and the result is a range that runs from 0 to 10, not including 10.
You can also use the closed range operator ...
to get a random integer from 0 to 10, including 10. Like this:
let number = Int.random(in: 0...10)
You can use the random(in:)
function to get random values for several primitive types, such as Int
, Double
, Float
and even Bool
. Like this:
let fraction = Float.random(in: 0..<1)
The above example returns a random floating-point value, i.e. a number with a fraction, between 0 and 1.
And the example below either returns true
or false
– a random boolean! They’re super useful for randomly testing conditional logic.
let stayOrGo = Bool.random()
What about picking a random element from an array? You can do that like this:
let names = ["Ford", "Zaphod", "Trillian", "Arthur", "Marvin"]
let randomName = names.randomElement()
In the above code you use randomElement()
on the names
array. You can use this function on any Collection
, such as arrays and dictionaries. Keep in mind that the returned random element is an optional.
Can you also use the new random functions in Swift 4.2. to shuffle an array? Yes! Randomizing the order of an array is surprisingly simple:
var names = ["Ford", "Zaphod", "Trillian", "Arthur", "Marvin"]
names.shuffle()
// `names` can now be: ["Zaphod", "Marvin", "Arthur", "Ford", "Trillian"]
The shuffle functions use Swift’s typical naming structure, so shuffle()
shuffles the array in-place, mutating the original array, and shuffled()
returns a copy of the shuffled array.
You can even shuffle a Sequence
, like this:
let sequence = 0 ..< 7
let shuffledSequence = sequence.shuffled()
// `shuffledSequence` can now be: [0, 6, 2, 3, 4, 1, 5]
Simple, right? Much simpler than the pre-4.2 arc4random_uniform(_:)
with all that type casting…
Are you using a Swift version lower than 4.2? Then use the random number functions in the chapters below.
Sign up for my iOS development course, and learn how to start your career as a professional iOS developer.
Swift has three typical functions for random numbers:
arc4random()
returns a random number between zero and 2^{32}–1arc4random_uniform(_:)
returns a random number between zero and the first parameter, minus one.drand48()
returns a random Double
between 0.0
and 1.0
Both arc4random()
and arc4random_uniform(_:)
use the UInt32
type instead of the more typical Int
.
It’s recommended to use the arc4random_uniform(_:)
instead of arc4random()
, because the latter suffers from a condition called “modulo bias”. This causes particular numbers to appear more often than others, undermining the “randomness” of the function.
Keep in mind that the random numbers from these functions are semi-random and they’re generated with a mathematical function. Although they appear random, if you repeat the random function often enough you’ll see patterns and repetitions. This is fine for games or shuffling an array, but you shouldn’t use these random functions for cryptography or security purposes.
Fun fact: early computers, and especially computer games, included a file with random numbers. The program would sequentially pick random numbers from this file whenever it needed a random number, instead of calculating a random number on its own!
These days the mechanism isn’t much different, although iOS or Android has a large reserve of randomly generated numbers. Calculating a large set of random numbers before using it is known as seeding.
The function arc4random_uniform(_:)
takes one parameter, the upper bound. It’ll return a random number between 0 and this upper bound, minus 1.
Like this:
arc4random_uniform(42)
// Output: 13
This will return a random number between 0 and 41. The result is of type UInt32
, so if you want to work with an ordinary integer in your code, you’ll have to convert or type cast it to Int
.
Like this:
let n = Int(arc4random_uniform(42))
Constant n
is now of type Int
, which is easier to work with.
What about doubles? As you know, a double is a decimal-point number with double precision. It’s most often used in Swift for number’s that have commas , or fractions.
This is how you generate a random double in Swift, between 0.0
and 1.0
:
let d = drand48()
print(d)
// Output: 0.396464773760275
Neat!
Quick note: all computers have trouble representing floating-point numbers and fractions, so logically, the drand48()
function works by simply putting a couple of integer numbers after each other…
Now, that arc4random_uniform(_:)
function is a bit odd to work with. Let’s write a convenience function to help you work with random numbers.
Like this:
func random(_ n:Int) -> Int {
return Int(arc4random_uniform(UInt32(n)))
}
This function takes an unnamed parameter n
of type Int
, and returns an integer number between 0 and n-1
. As you can see, inside the arc4random_uniform(_:)
call, n
is converted to UInt32
, and the return value of arc4random_uniform(_:)
is converted back to Int
.
If you’re using Swift 4.2. or greater, you won’t need these convenience functions. Simply use .random()
or .randomElement()
, as explained in the chapters above.
Next, you can generate a few random numbers like this:
for i in 0...100 {
print(random(100))
}
This will output a 100 random numbers between 0 and 99.
Swift has a half-open range operator, like this 0..<42
. Why don’t you use it to change the convenience function?
Like this:
func random(_ range:Range<Int>) -> Int
{
return range.lowerBound + Int(arc4random_uniform(UInt32(range.upperBound - range.lowerBound)))
}
Instead of a single input number, this function takes in a Range
like 0..<42
and returns a number between 0 and 42, not including 42.
Inside the function the result is first added to the lower bound of the range, ensuring that the random number always starts at that lower bound. Inside the arc4random_uniform(_:)
function, the lower bound is subtracted from the upper bound so that the returned result lies neatly between the lower and the upper bound.
This function deliberately uses the half-open range generic type Range
, instead of the closed range generic ClosedRange
, because it better reflects the range of the resulting numbers from arc4random_uniform(_:)
.
You can use the random-number-from-range function like this:
for i in 0...100 {
print(random(1..<42))
}
This will print out a 100 random numbers between 1 and 41.
How do you get a random number from an array?
As you know the function arc4random_uniform(_:)
returns an integer between zero and the upper bound. If we use array.count
as the upper bound, the function will return an index number within the bounds of the array!
Like this:
let names = ["Arthur", "Ford", "Zaphod", "Marvin", "Trillian"]
let random = names[Int(arc4random_uniform(UInt32(names.count)))]
print(random)
// Output: Marvin
In this example, a random number between zero and names.count
is created, and that’s used to get a value out of the names
array with subscript syntax.
You can conveniently turn the example above in an extension for Array
, like this:
extension Array
{
func random() -> Element {
return self[Int(arc4random_uniform(UInt32(self.count)))]
}
}
In the same fashion as before, a random element from the array is returned. In the example above, Element
refers to a type alias of the element in the array, and self
refers to the current array instance.
You can use it like this:
let names = ["Arthur", "Ford", "Zaphod", "Marvin", "Trillian"]
print(names.random())
// Output: Trillian
What about shuffling an array? Check out this tutorial: Shuffling Arrays in Swift with Fisher-Yates
What if you want to generate a random string? You can do that like this:
func randomString(_ n: Int) -> String
{
let digits = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
var result = ""
for _ in 0..<n {
result += String(digits.randomElement()!)
}
return result
}
In the above example you define a function random(_:)
that takes one unnamed parameter n
of type Int
. The function then defines an alphabet – the characters it’s going to choose from randomly. In the for-loop, a random character from the string is selected and then appended to variable result
. This variable is then returned at the end of the function.
Below’s a more concise version of the above randomString(_:)
function. It works by mapping a range of integers into random characters from digits
, which is then converted back into a String
.
func randomString(_ n: Int) -> String {
let digits = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
return String(Array(0..<n).map { _ in digits.randomElement()! })
}
You use the function like this:
let password = randomString(24)
print(password)
// Output: qGUjakGkjlRb1sd5jDaj2raW
A few things to keep in mind:
Sign up for my iOS development course, and learn how to start your career as a professional iOS developer.
Awesome! We generated a whole bunch of random stuff. Here’s what we discussed:
Want to learn more? Check out these resources:
Hi, I'm Reinder.
I help developers play with code.
Start your iOS career
Learn how in my free 7-day course
No spam, ever. Unsubscribe anytime. Privacy Policy