7

I read in https://www.hackingwithswift.com/read/35/2/generating-random-numbers-in-ios-8-and-earlier that the best way to generate a random number is to use

    let r = arc4random_uniform(UInt32(_names.count))
    let name : String = _names[Int(r)]

but it seems odd that I have to cast twice to be able to get a random number, what should I do to avoid casting?

6 Answers6

7

It really depends on how much casting you want to avoid. You could simply wrap it in a function:

func random(max maxNumber: Int) -> Int {
    return Int(arc4random_uniform(UInt32(maxNumber)))
}

So then you only have to do the ugly casting once. Everywhere you want a random number with a maximum number:

let r = random(max: _names.count)
let name: String = _names[r]

As a side note, since this is Swift, your properties don't need _ in front of them.

tktsubota
  • 9,371
  • 3
  • 32
  • 40
3

I really like using this extension

extension Int {
    init(random range: Range<Int>) {

        let offset: Int
        if range.startIndex < 0 {
            offset = abs(range.startIndex)
        } else {
            offset = 0
        }

        let min = UInt32(range.startIndex + offset)
        let max = UInt32(range.endIndex   + offset)

        self = Int(min + arc4random_uniform(max - min)) - offset
    }
}

Now you can generate a random Int indicating the range

let a = Int(random: 1...10) // 3
let b = Int(random: 0..<10) // 6
let c = Int(random: 0...100) // 31
let d = Int(random: -10...3) // -4
Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
2

Swift 4.2 and above

You can initial a random element:

let randomInt = Int.random(in: 0...1)
let randomDouble = Double.random(in: 0...1)

Also You can take a random element from a collection like

let randomInt = (0...9).randomElement()

Also there is another handy method that you can use on array for shuffling that you may need:

let shuffled = [1, 2, 3, 4].shuffled()
Community
  • 1
  • 1
Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278
1

you can use gameplaykit

let random = GKRandomDistribution(lowestValue: 0, highestValue: 100)
let r = random.nextInt()
chiarotto.alessandro
  • 1,491
  • 1
  • 13
  • 31
  • 2
    It depends on the usage, Apple docs state: *The randomization services provided in GameplayKit are suitable for reliably creating deterministic, pseudorandom gameplay mechanics, but are **not cryptographically robust**. For cryptography, obfuscation, or cipher uses, use the Security framework, described in Cryptographic Services Guide*. `arc4random()` and `arc4random_uniform()` are cryptographically robust. – zaph Feb 18 '16 at 00:36
1

Modified answer from Luca written as extension in Swift 4

/// Returns random number within given range, upper bound included, eg. -1...0 = [-1, 0, 1]
extension CountableClosedRange where Bound == Int
{
    var random: Int
    {
        let range = self
        let offset: Int = range.lowerBound < 0 ? abs(range.lowerBound) : 0
        let min = UInt32(range.lowerBound + offset)
        let max = UInt32(range.upperBound + offset)
        let randomNumber = Int(min + arc4random_uniform(max - min + 1)) - offset

        return randomNumber
    }
}

/// Returns random number within given range, upper bound not included, eg. -1...0 = [-1, 0]
extension CountableRange where Bound == Int
{
    var random: Int
    {
        let range = self
        let offset: Int = range.lowerBound < 0 ? abs(range.lowerBound) : 0
        let min = UInt32(range.lowerBound + offset)
        let max = UInt32(range.upperBound + offset)
        let randomNumber = Int(min + arc4random_uniform(max - min)) - offset

        return randomNumber
    }
}

Examples:

(0...10).random
(0..<10).random
El Horrible
  • 161
  • 9
0

Or you could use

 let name : String = _names[ Int(arc4random()) % _names.count ]
Alain T.
  • 40,517
  • 4
  • 31
  • 51
  • The OP is selecting a name out of a list. This hardly qualifies as a valid scenario where modulo bias can make any relevant difference. With 4096 names in the list, the bias would be 0.000096 % on half of the entries – Alain T. Feb 18 '16 at 13:03
  • Why is it better to use `arc4random()` than `arc4random_uniform()`. The question is about casting with `arc4random_uniform`? – zaph Feb 18 '16 at 13:45
  • 1
    It's not better it's just shorter to write, and as such it is a viable alternative given the OP's objective. – Alain T. Feb 18 '16 at 18:29
  • 2
    One does not compromise correctness for "shorter to write", writing code is what we do, when writing code and we should not settle for worse code (even a little bit) to save typing `UInt32()`. Perhaps that is why we are not truly professionals yet, we are to lazy or do not care enough to type eight additional characters. – zaph Feb 18 '16 at 19:04