'Why am I getting an expected expression for my else if lines in SWIFT Xcode? (Basic)

I am completely new to coding and have been learning through sources such as skillshare and Udemy. In one of the projects, I was asked to create a simple app which has the features of a random number generator from 1-100. The number placed in the text input should then tell us if the input number was more or less than the randomly generated number.

The code is as follows:

@IBOutlet weak var numberText: UITextField!

@IBAction func guessButton(_ sender: Any) {
    randomNumber(guess: "guess")
}
@IBOutlet weak var answerText: UILabel!

var random = arc4random_uniform(100);

func randomNumber (guess: String) {
    if Int(numberText.text!) != nil {
        let numGuess = Int(numberText.text!);
        let random = Int(arc4random_uniform(100));
    else if numGuess! > random {
            answerText.text = "try a smaller number"
    else if numGuess! < random {
            answerText.text = "try a larger number"
            }
    else if numGuess! == random {
            }
        }

        answerText.text = "you got it right, the answer is \(numGuess)!"

    } else {
        answerText.text = "Try typing numbers from 1-100"
    }
}

I would like to know why I am getting the error "expected expression" for my else if codes. Also, is it possible to do this with the switch case?

I am not sure if my method is even the right way of creating this app, so please feel free to give me some pointers!



Solution 1:[1]

The required syntax for if - else statements is

if condition1 {
   // condition1 is true
} else if condition2 {
   // condition2 is true
} else {
  //
}

All braces must be balanced.

Your code cleaned up and with a better number check is supposed to be

func randomNumber() { // The `guess: String` parameter is not used
    
    if let number = numberText.text, let numGuess = Int(number), 1...100 ~= numGuess {

        // Int.random creates numbers between 0 and 99
        let random = Int.random(in: 0..<100)
        
        if numGuess > random {
            answerText.text = "try a smaller number"
            
        } else if numGuess < random {
            answerText.text = "try a larger number"
            
        } else { // the numbers are equal
            answerText.text = "you got it right, the answer is \(numGuess)"
        }
    
    } else {
        answerText.text = "Try typing numbers from 1-100"
    }
}

Solution 2:[2]

First the answer, followed by a few explanations. (Actually an assumption first!)

My Assumption:

You have two UILabels declared someplace.

var numberText = UILabel()
var answerText = UILabel()

These may be in code (like I've done or otherwise) or in IB and you have IBOutlets hooked up.

Now the code:

func randomNumber (guess: String) {

    let numGuess = Int(numberText.text!)
    let random = Int(arc4random_uniform(100))

    if Int(numberText.text!) != nil {
    } else if numGuess! > random {
        answerText.text = "try a smaller number"

    } else if numGuess! < random {
        answerText.text = "try a larger number"
    } else if numGuess! == random {
        answerText.text = "you got it right, the answer is \(numGuess)!"

    } else {
        answerText.text = "Try typing numbers from 1-100"
    }
}

Finally, some explanations:

  • As indicated in another answer, your if...else brackets are misplaced. The proper syntax is:

    if [condition] {
        // do something here
    } else if {
        // do something else here
    } else {
        // do yet a different thing here
    }
    

Please note the closing brakes *before the else if or else. But I'm thinking this may be a simple type on your part, and the real issue with your code is....

  • Something called variable scope.

Note my movement of these two lines of code:

let numGuess = Int(numberText.text!);
let random = Int(arc4random_uniform(100));

Since they are inside the **first* part of the if ... else if ... else clause, they are not available (accessible) in the other parts. Moving them outside of the entire 'if statement makes them available.

Edit

A new issue - unwrapping a bad value - is happening now. Let's look at one line of code, then a second:

} else if numGuess! > random {

This is the line giving you an issue. Obviously, numGuess is the problem. Just as obviously, it's not an Int. So let's look at a second line:

let numGuess = Int(numberText.text!);

Several things wrong here. First - and extremely minor - the semi-colon. Get rid of it. It's not needed, and not "Swifty".

Next though, at least until you know what going on, it's doing too much. You can break it down into a few lines, and this will help debug things:

let strGuess = numberText.text!  // this is an unwrapped staring representing what's in this textfield
let intGuess = Int(strGuess) // this is an Int representation of what was entered

While this may help figure out the issue, it's very poorly coded. What happens if nothing was entered in the textfield? What happens if "abc" or "123abc" was entered? You are looking at a process error - exactly what you have now.

Some background - your original question had a build error. It had no idea what numGuess was because it was not in scope. I moved it, correcting the build error, but because of how you declared the numberText control, it now generates a processing error.

One more very confusing thing on your end - why is your function randomNumber(guess:) never using the input parameter guess?

Here's what you can do:

// Some declaration of numberText here. Please, include this next time.

// Where you need to call randomNumber()

    answerText.text = randomNumber(guess: numberText.text)

// Note several changes 

func randomNumber (guess: String?) -> String {

    guard let guess = guess, let numGuess = Int(guess) else {
        return "try typing in a number"
    }
    let random = Int(arc4random_uniform(100))
    if numGuess > random {
        return "try a smaller number"
    } else if numGuess < random {
        return "try a larger number"
    } else if numGuess == random {
        return "you got it right, the answer is \(numGuess)!"
    } else {
        return "Try typing numbers from 1-100"
    }
}

Changes:

  • Your function now takes an optional string and returns the answer as a string. This means (1) you don't address global UITextfield inside a function, making it more portable, and (2) the function call itself doesn't need to do any unwrapping.
  • Using a guard statement immediately inside the function not only check for nil, it tries to see if the guess is indeed an number. If it fails on either part, it "gently returns a string informing the user that an invalid entry was made.
  • Finally, if it passes the guard statement, no further unwrapping is needed!

Let me know if you have additional issues with this code - I'll edit.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2