chris3365
chris3365

Reputation: 23

Swift Calculator: operator precedence issue

I'm trying to develop a calculator's app in swift.

My main issue is that my calculator doesn't follow operator precedence.

For example: 1 + 1 * 8 = 9 //it's the right answer

But instead: 1 + 1 * 8 = 16 //in my calculator, which is the wrong answer

I'm following a MVC pattern. Here is my Model:

class CountOnMeBrain {

//MARK: - Properties
var stringNumbers: [String] = [String()]
var operators: [String] = ["+"]
var index = 0
var countOnMeDelegate: CountOnMeDelegate?
var isExpressionCorrect: Bool {
    if let stringNumber = stringNumbers.last {
        if stringNumber.isEmpty {
            if stringNumbers.count == 1 {
                countOnMeDelegate?.alertShow(title: "Zéro!", message: "Démarrez un nouveau calcul!")
            } else {
                countOnMeDelegate?.alertShow(title: "Zéro!", message: "Entrez une expression correcte!")
            }
            return false
        }
    }
    return true
}

var canAddOperator: Bool {
    if let stringNumber = stringNumbers.last {
        if stringNumber.isEmpty {
            countOnMeDelegate?.alertShow(title: "Zéro!", message: "Expression incorrecte!")
            return false
        }
    }
    return true
}

//MARK: - Methods
func addNewNumber(_ newNumber: Int) {
    if let stringNumber = stringNumbers.last {
        var stringNumberMutable = stringNumber
        stringNumberMutable += "\(newNumber)"
        stringNumbers[stringNumbers.count-1] = stringNumberMutable
    }
    updateDisplay()
}

func calculateTotal() {
    if !isExpressionCorrect {
        return
    }
    var total = Double()
    for (index, stringNumber) in stringNumbers.enumerated() {
        let number = Double(stringNumber)
        switch operators[index] {
        case "+":
            total += number!
        case "-":
            total -= number!
        case "÷":
            total /= number!
        case "x":
            total *= number!
        default:
            break
        }
    }
    countOnMeDelegate?.updateTextView(label: "\(total)")
    clear()
}

func clear() {
    stringNumbers = [String()]
    operators = ["+"]
    index = 0
}

func divide() {
    if canAddOperator {
        operators.append("÷")
        stringNumbers.append("")
        updateDisplay()
    }
}

func multiply() {
    if canAddOperator {
        operators.append("x")
        stringNumbers.append("")
        updateDisplay()
    }
}

func minus() {
    if canAddOperator {
        operators.append("-")
        stringNumbers.append("")
        updateDisplay()
    }
}

func plus() {
    if canAddOperator {
        operators.append("+")
        stringNumbers.append("")
        updateDisplay()
    }
}

func updateDisplay() {
    var text = ""
    for (index, stringNumber) in stringNumbers.enumerated() {
        // Add operator
        if index > 0 {
            text += operators[index]
        }
        // Add number
        text += stringNumber
    }
    countOnMeDelegate?.updateTextView(label: text)
}

}

Here is my Controller:

class ViewController: UIViewController {

//MARK: - Outlets
@IBOutlet weak var textView: UITextView!
@IBOutlet var numberButtons: [UIButton]!
@IBOutlet var operatorButtons: UIButton!

//MARK: - Properties
var countOnMeBrain = CountOnMeBrain()

//MARK: - View Life Cycle
override func viewDidLoad() {
    super.viewDidLoad()
    countOnMeBrain.countOnMeDelegate = self
}

//MARK: - Action
@IBAction func tappedNumberButton(_ sender: UIButton) {
    for (index, numberButton) in numberButtons.enumerated() where sender == numberButton {
        countOnMeBrain.addNewNumber(index)
    }
}

@IBAction func tappedOperatorButton(_ sender: UIButton) {
    switch sender.tag {
    case 1:
        countOnMeBrain.plus()
    case 2:
        countOnMeBrain.minus()
    case 3:
        countOnMeBrain.multiply()
    case 4:
        countOnMeBrain.divide()
    case 5:
        countOnMeBrain.calculateTotal()
    default:
        break
    }
}

}

I am a beginner in swift so all your precious advices are welcomed. Sorry for my poor english. Thank you.

Upvotes: 0

Views: 685

Answers (1)

Alex Posplaw
Alex Posplaw

Reputation: 116

First of all, using IBOutlet collection leads to unexpected order of buttons and you better use UIView's tag property in your Storyboard/XIB to store button's integer value and use it instead of index here:

@IBAction func tappedNumberButton(_ sender: UIButton) {
    countOnMeBrain.addNewNumber(sender.tag)
}

Secondly, as per your calculateTotal method it calculates correctly. The only incorrect thing is your method's inner logic, because it executes calculation step by step ignoring operator precedence. Unfortunately, StackOverflow isn't place for helping with algorithms. Please rewrite it according to desired logic to receive proper result.

Upvotes: 1

Related Questions