NullHypothesis NullHypothesis - 1 month ago 26
iOS Question

Swift3 Random Extension Method

I was using this extension method to generate a random number:

func Rand(_ range: Range<UInt32>) -> Int {
return Int(range.lowerBound + arc4random_uniform(range.upperBound - range.lowerBound + 1))
}


I liked it b/c it was no nonsense, you just called it like this:

let test = Rand(1...5) //generates a random number between 1 and 5


I honestly don't know why things need to be so complicated in Swift but I digress..

So i'm receiving an error now in Swift3

No '...' candidates produce the expected contextual result type 'Range<UInt32>'


Would anyone know what this means or how I could get my awesome Rand function working again? I guess x...y no longer creates Ranges or x..y must be explicitly defined as UInt32? Any advice for me to make things a tad easier?

Thanks so much, appreciate your time!

Answer

In Swift 3 there are four Range structures:

  • "x" ..< "y"Range<T>
  • "x" ... "y"ClosedRange<T>
  • 1 ..< 5CountableRange<T>
  • 1 ... 5CountableClosedRange<T>

(The operators ..< and ... are overloaded so that if the elements are stridable (random-access iterators e.g. numbers and pointers), a Countable Range will be returned. But these operators can still return plain Ranges to satisfy the type checker.)

Since Range and ClosedRange are different structures, you cannot implicitly convert a them with each other, and thus the error.

If you want Rand to accept a ClosedRange as well as Range, you must overload it:

// accepts Rand(0 ..< 5)
func Rand(_ range: Range<UInt32>) -> Int {
    return Int(range.lowerBound + arc4random_uniform(range.upperBound - range.lowerBound))
}

// accepts Rand(1 ... 5)
func Rand(_ range: ClosedRange<UInt32>) -> Int {
    return Int(range.lowerBound + arc4random_uniform(range.upperBound + 1 - range.lowerBound))
}