0

I am teaching myself Swift and am stuck with a Random function.

What I want to achieve: User is able to specify the min and max of the Range.

Code I have now for the button, where I believe I am declaring the text as an integer:

@IBAction func generateNumbers(sender: AnyObject) {

    let minRange:Int? = Int(lowValue.text!)
    let maxRange:Int? = Int(highValue.text!)

    func randomNumber(range: Range<Int> = minRange...maxRange) -> Int {
        let min = range.startIndex
        let max = range.endIndex
        return Int(arc4random_uniform(UInt32(max - min))) + min
    }
}

Obviously minRange and maxRange aren't valid integers for the Range, I am just wondering where I'm going wrong.

Thanks in advance for any assistance.

3
  • You need to unwrap minRange and maxRange and it'll work. Commented Jun 19, 2016 at 13:42
  • Okay I'll look into unwrapping. Thank you very much! Commented Jun 19, 2016 at 13:44
  • "Optionals". Very important. :) Read this: developer.apple.com/library/ios/documentation/Swift/Conceptual/… Commented Jun 19, 2016 at 13:45

2 Answers 2

2

You are almost there

The problem is that

let minRange:Int? = Int(lowValue.text!)
let maxRange:Int? = Int(highValue.text!)

are defined as optionals.

While here

func randomNumber(range: Range<Int> = minRange...maxRange) -> Int {

you need minsRange and maxRange to be non optional.

So you could use the guard let statement to safely perform the needed unwrappings

@IBAction func generateNumbers(sender: AnyObject) {

    guard let
        lowText = lowValue.text,
        highText = highValue.text,
        minRange = Int(lowText),
        maxRange = Int(highText)
    else {
        print("Couldn't find valid integers inside lowValue and highValue UITextFields. So I'm giving up...")
        return
    }

    func randomNumber(range: Range<Int> = minRange...maxRange) -> Int {
        let min = range.startIndex
        let max = range.endIndex
        return Int(arc4random_uniform(UInt32(max - min))) + min
    }
}

Invoking randomNumber

Of course don't forget to finally invoke your function randomNumber(1...10)

Update

@IBAction func generateNumbers(sender: AnyObject) {

    guard let
        lowText = lowValue.text,
        highText = highValue.text,
        minRange = Int(lowText),
        maxRange = Int(highText)
        else {
            print("Couldn't find valid integers inside lowValue and highValue UITextFields. So I'm giving up...")
            return
    }

    let result = Int(arc4random_uniform(UInt32(minRange - maxRange))) + minRange

}
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks so much I will try this now! :)
Unfortunately I receive this error: Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc failed with exit code 1
@PeterG: interesting error. I think the problem is about the default parameter value used into randomNumber. Infact providing an explicitt value randomNumber(1...100) seems to solve the error. If you want I can provide you a workaround.
I can get it working in Playground like this: let lowValue = "10" let highValue = "50" let minRange:Int? = Int(lowValue) let maxRange:Int? = Int(highValue) func randomNumber(range: Range<Int> = minRange!...maxRange!) -> Int { let min = range.startIndex let max = range.endIndex return Int(arc4random_uniform(UInt32(max - min))) + min } let results = randomNumber()
@PeterG: it is working only because you removed the parent function (which seems to be the problem). In your code you are using ! which I suggest you to avoid. Just take a look at the updated section in my answer.
|
1

As others have identified, your minRange and maxRange are Optionals. They need to be Int, not Int? in order to form the range.

Also, you should avoid using ! to unwrap the text fields, just in case they're nil.

If you have some reasonable defaults for minRange and maxRange (such as 1 and 10), you could use the nil coalescing operator to unwrap your text fields and replace the values with defaults if the text fields can't be converted to an Int:

@IBAction func generateNumbers(sender: AnyObject) {

    let minRange = Int(lowValue.text ?? "") ?? 1
    let maxRange = Int(highValue.text ?? "") ?? 10

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

    // test
    let results = randomNumber(minRange...maxRange)
    self.field1.text = String(results)
}

Note: The compiler is not happy with using the values minRange and maxRange to set the default value for range, so I added them to the call of randomNumber.


There is another potential gotcha here as well. You can't form a range if minRange is larger than maxRange, so you should check for that as well:

var minRange = Int(lowValue.text ?? "") ?? 1
var maxRange = Int(highValue.text ?? "") ?? 10
if minRange > maxRange {
    // Swap 'em
    (minRange, maxRange) = (maxRange, minRange)
}

Why even torture yourself in creating the range anyway? Since randomNumber is declared inside of generateNumbers you can just use minRange and maxRange:

@IBAction func generateNumbers(sender: AnyObject) {

    var minRange = Int(lowValue.text ?? "") ?? 1
    var maxRange = Int(highValue.text ?? "") ?? 10
    if minRange > maxRange {
        // Swap 'em
        (minRange, maxRange) = (maxRange, minRange)
    }

    func randomNumber() -> Int {
        return Int(arc4random_uniform(UInt32(maxRange - minRange))) + minRange
    }

    //test
    let results = randomNumber()
    self.field1.text = String(results)
}

6 Comments

This looks like a nice and simple way to do it, thank you. However, it kept coming up with an error requesting I insert a ; separator, which didn't work either.
Which line specifically requested the ;?
Actually just copy pasting your code in only resulted in an error at run. So I'm probably doing something wrong. Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/u‌​sr/bin/swiftc failed with exit code 1
Make sure all of your @IBOutlets are wired up.
Check out my latest update. You don't even need to bother creating the range.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.