Create calculator history array swift - ios

I have created a calculator and have created a Model.swift to handle all of my calculations. Then everything else is handled in my ViewController.swift. I'm trying to add another functionality, I am looking to create a history of all the operations performed in my calculator i have made and store them in an array.
Here is my code so far:
ViewController.swift
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var displayLabel: UILabel!
#IBOutlet weak var HistoryLabel: UILabel!
var historyArray: [String] = []
var userIsTypingNumbers = false
var firstNumber = 0
var secondNumber = 0
#IBAction private func NumbersEntered(_ sender: UIButton) {
//know what number is being pressed
/*let digit = sender.currentTitle!
//if user is typing a number, do this.
if userIsTypingNumbers{
//specify what number is being pressed
let textCurrentDisplay = displayLabel.text!
//append the another number onto the previous number.
displayLabel.text = textCurrentDisplay + digit
} else {
displayLabel.text = digit
}
userIsTypingNumbers = true*/
/*addToHistory(recordToAddToHistory: digit)*/
let number = sender.currentTitle
if userIsTypingNumbers {
displayLabel.text = displayLabel.text! + number!
} else {
displayLabel.text = number
userIsTypingNumbers = true
}
}
var displayValue: Double {
get {
return Double(displayLabel.text!)!
}
set {
displayLabel.text = String(newValue)
}
}
private var calculations = PerformCalculations()
#IBAction func Enter(_ sender: UIButton) {
//perform the calculations
if userIsTypingNumbers{
calculations.setOperand(operand: displayValue)
userIsTypingNumbers = false
}
if let mathematicalSymbol = sender.currentTitle {
calculations.performOperation(symbol: mathematicalSymbol)
/*addToHistory(recordToAddToHistory: String(mathematicalSymbol))*/
}
/*HistoryLabel.text = HistoryLabel.text! + String(sender.currentTitle!)*/
displayValue = calculations.result
/*HistoryLabel.text = HistoryLabel.text! + String(displayValue)*/
/*historyArray.append("\(String(describing: HistoryLabel.text))")*/
}
#IBAction func Clear(_ sender: UIButton) {
//clear display to 0.
displayLabel.text = "0"
HistoryLabel.text = ""
}
#IBAction func Delete(_ sender: UIButton) {
//deleting last typed number, if user messed up.
let name: String = self.displayLabel.text!
//count number of characters.
let stringLength = name.characters.count
let substringIndex = stringLength - 1
displayLabel.text = (name as NSString).substring(to: substringIndex)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "History"){
if let destinationVC = segue.destination as? HistoryClassViewController{
destinationVC.someData = HistoryLabel.text
}
}
}*/
}
Model.swift
import Foundation
enum Optional<T>{
case None
case Some(T)
}
class PerformCalculations {
private var accumulator = 0.0
func setOperand(operand: Double){
accumulator = operand
}
//performing the operations for various operands
private var operations: Dictionary<String, Operation> = [
"√" : Operation.UnaryOperation(sqrt), //sqrt,
"×": Operation.BinaryOperation({$0 * $1}),
"+": Operation.BinaryOperation({$0 + $1}),
"-": Operation.BinaryOperation({$0 - $1}),
"÷": Operation.BinaryOperation({$0 / $1}),
"=": Operation.Equals
]
//case for various operands
private enum Operation{
case Constant(Double)
case UnaryOperation((Double) -> Double)
case BinaryOperation((Double, Double) -> Double)
case Equals
}
//switch case to actually perform the operations
func performOperation(symbol: String){
if let operation = operations[symbol]{
switch operation{
case .Constant(let value): accumulator = value
case .BinaryOperation(let function):
executePendingBinaryOperation()
pendingVar = PendingBianryOperationInfo(binaryFunction: function, firstOperand: accumulator)
case .UnaryOperation(let foo): accumulator = foo(accumulator)
case .Equals:
executePendingBinaryOperation()
}
}
}
private func executePendingBinaryOperation(){
if pendingVar != nil{
accumulator = pendingVar!.binaryFunction(pendingVar!.firstOperand,accumulator)
pendingVar = nil
}
}
private var pendingVar: PendingBianryOperationInfo?
private struct PendingBianryOperationInfo{
var binaryFunction: (Double, Double) -> Double
var firstOperand: Double
}
var result: Double{
get{
return accumulator
}
}
}
Any help would be appreciated, thank you very much!

I have solved my problem. Here is the updated code, incase it ever comes in handy for someone.
ViewController.swift
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var displayLabel: UILabel!
#IBOutlet weak var HistoryLabel: UILabel!
var historyArray: [String] = []
var userIsTypingNumbers = false
var firstNumber = 0
var secondNumber = 0
var operation = ""
var result = 0.0
#IBAction private func NumbersEntered(_ sender: UIButton) {
//know what number is being pressed
let number = sender.currentTitle
//if user is typing number, do this.
if userIsTypingNumbers {
//specify what number is being pressed.
//append the number onto the previous number.
displayLabel.text = displayLabel.text! + number!
} else {
displayLabel.text = number
userIsTypingNumbers = true
}
}
var displayValue: Double {
get {
return Double(displayLabel.text!)!
}
set {
displayLabel.text = String(newValue)
}
}
private var calculations = PerformCalculations()
#IBAction func OperationsPressed(_ sender: UIButton) {
userIsTypingNumbers = false
firstNumber = Int(Double(displayLabel.text!)!)
operation = sender.currentTitle!
if operation == "√" {
result = (PerformCalculations().squareroot(a: Double(firstNumber)))
displayLabel.text = String(result)
}
}
#IBAction func Enter(_ sender: UIButton) {
userIsTypingNumbers = false
secondNumber = Int(Double(displayLabel.text!)!)
if operation == "+" {
result = (PerformCalculations().add(a: Double(firstNumber), b: Double(secondNumber)))
} else if operation == "÷" {
result = (PerformCalculations().division(a: Double(firstNumber), b: Double(secondNumber)))
} else if operation == "×" {
result = (PerformCalculations().multiplication(a: Double(firstNumber), b: Double(secondNumber)))
} else if operation == "-" {
result = (PerformCalculations().subtract(a: Double(firstNumber), b: Double(secondNumber)))
}
displayLabel.text = String(result)
historyArray.append("\(firstNumber) \(operation) \(secondNumber) = \(result)")
userIsTypingNumbers = false
//self.performSegue(withIdentifier: "History", sender: self)
}
#IBAction func Clear(_ sender: UIButton) {
//clear display to 0.
displayLabel.text = "0"
}
#IBAction func Delete(_ sender: UIButton) {
//deleting last typed number, if user messed up.
let name: String = self.displayLabel.text!
//count number of characters.
let stringLength = name.characters.count
let substringIndex = stringLength - 1
displayLabel.text = (name as NSString).substring(to: substringIndex)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "History" {
if let destinationVC = segue.destination as? TableTableViewController {
destinationVC.dataString = historyArray.description
}
}
}*/
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destViewController : TableTableViewController = segue.destination as! TableTableViewController
destViewController.dataString = historyArray.description
}
}
Model.swift
import Foundation
class PerformCalculations {
func add(a: Double, b: Double) -> Double {
let result = a + b
return result
}
func division(a: Double, b: Double) -> Double {
let result = a / b
return result
}
func subtract(a: Double, b: Double) -> Double {
let result = a - b
return result
}
func multiplication(a: Double, b: Double) -> Double {
let result = a * b
return result
}
func squareroot(a: Double) -> Double {
let result = sqrt(a)
return result
}
}

Related

How to index an int array via button?

My code appends ints to an array. There is no sorting. I would like to index every entry to the array. Sort the array from smallest to largest.
import UIKit
class ViewController: UIViewController {
#IBOutlet var enterText: UITextField!
var arrayOfInt = [Int]()
#IBAction func submitText(_ sender: Any) {
if let text = enterText.text {
if let number = Int(text) {
arrayOfInt.append(number)
print(arrayOfInt)
} else {
print("Please enter number")
}
}
}
}
You can use like this :
#IBAction func submitText(_ sender: Any) {
if let text = enterText.text {
if let number = Int(text) {
var index = 0
for num in arrayOfInt {
if num > number {
arrayOfInt.insert(number, at: index)
break
}
index += 1
}
print(arrayOfInt)
} else {
print("Please enter number")
}
}
}

Change a button background on click of another button

I use this code so that when I click on a button its background changes to a picture with a white border and when I press it again it changes to a picture with a gray background (the button always has a gray background).
How can I do so that when I click on another button (clear and equal), the background of the "+", "-", "/", "*" changes to gray as it was before pressing.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var displayResultLabel: UILabel!
var stillTyping = false
var dotIsPlaced = false
var firstOperand: Double = 0
var secondOperand: Double = 0
var operationSign: String = ""
var currentInput: Double {
get {
return Double (displayResultLabel.text!)!
}
set {
let value = "\(newValue)"
let ValueArray = (value.components(separatedBy:"."))
if ValueArray[1] == "0" {
displayResultLabel.text = "\(ValueArray[0])"
} else {
displayResultLabel.text = "\(newValue)"
}
stillTyping = false
}
}
#IBAction func numberPressed(_ sender: UIButton) {
let number = sender.currentTitle!
if stillTyping {
if (displayResultLabel.text?.characters.count)! < 20 {
displayResultLabel.text = displayResultLabel.text! + number
}
} else {
displayResultLabel.text = number
stillTyping = true
}
}
#IBAction func twoOperandsSignPressed(sender: UIButton) {
operationSign = sender.currentTitle!
firstOperand = currentInput
stillTyping = false
dotIsPlaced = false
}
func operateWithTwoOperands(operation: (Double, Double) -> Double) {
currentInput = operation(firstOperand, secondOperand)
stillTyping = false
}
#IBAction func equalitySignPressed(sender: UIButton) {
if stillTyping {
secondOperand = currentInput
}
dotIsPlaced = false
switch operationSign {
case "+":
operateWithTwoOperands{$0 + $1}
case "-":
operateWithTwoOperands{$0 - $1}
case "✕":
operateWithTwoOperands{$0 * $1}
case "÷":
operateWithTwoOperands{$0 / $1}
default: break
}
}
#IBAction func clearButtonPressed(_ sender: UIButton) {
firstOperand = 0
secondOperand = 0
currentInput = 0
displayResultLabel.text = "0"
dotIsPlaced = false
operationSign = ""
}
// +,-
#IBAction func plusMinusButtonPressed(_ sender: UIButton) {
currentInput = -currentInput
}
#IBAction func percentageButtonPressed(_ sender: UIButton) {
if firstOperand == 0 {
currentInput = currentInput / 100
} else {
secondOperand = firstOperand * currentInput / 100
}
}
#IBAction func squareRootButtonPressed(_ sender: UIButton) {
currentInput = sqrt(currentInput)
}
#IBAction func dotButtonPressed(_ sender: UIButton) {
if stillTyping && !dotIsPlaced {
displayResultLabel.text = displayResultLabel.text! + "."
dotIsPlaced = true
} else if !stillTyping && !dotIsPlaced {
displayResultLabel.text = "0."
}
#IBAction func PercentAnimate(_ sender: UIButton) {
if sender.currentBackgroundImage == image_off {
sender.setBackgroundImage(Image_on, for: .normal)
} else {
sender.setBackgroundImage(image_off, for: .normal)
}
if (previousButton !== sender) {
previousButton.setBackgroundImage(image_off, for: .normal)
previousButton = sender
}
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}
Here is the code you can Create border to any View, in your case it will be button.
func createBordersWithColor(color: UIColor, myView : UIView) {
myView.layer.borderWidth = 1
myView.layer.cornerRadius = 0
myView.layer.shouldRasterize = false
myView.layer.rasterizationScale = 2
myView.clipsToBounds = true
myView.layer.masksToBounds = true
let cgColor: CGColor = color.cgColor
myView.layer.borderColor = cgColor
}
You can use the above function with you code like
#IBAction func PercentAnimate(_ sender: UIButton) {
let btnCurrent : UIButton = sender as! UIButton
let btnPrevious : UIButton = previousButton as! UIButton
createBorderWithColor(color : UIColor.clear , myView : btnPrevious)
createBorderWithColor(color : UIColor.clear , myView : btnCurrent)
if (previousButton !== sender) {
previousButton = sender
}
}
let know if it helps, or you need any explanation.
If you want to set with image
#IBAction func PercentAnimate(_ sender: UIButton) {
let btnCurrent : UIButton = sender as! UIButton
let btnPrevious : UIButton = previousButton as! UIButton
btnPrevious.setBackgroundImage(image_off, for: .normal)
btnCurrent.setBackgroundImage(image_on, for: .normal)
if (previousButton !== sender) {
previousButton = sender
}
}

Error - EXC_BREAKPOINT (code=1, subcode=0x100308448)

error - EXC_BREAKPOINT (code=1, subcode=0x100308448)
Every time I try to double-click the divide button, Xcode issues EXC_BREAKPOINT (code = 1, subcode = 0x100308448), and my application crashes. Can you please help me solving this issue?
Dividing button - EXC_BREAKPOINT(...)
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var displayResultLabel: UILabel!
var stillTyping = false
var dotIsPlaced = false
var firstOperand: Double = 0
var secondOperand: Double = 0
var operationSign: String = ""
var currentInput: Double {
get {
return Double (displayResultLabel.text!)!
}
set {
let value = "\(newValue)"
let ValueArray = (value.components(separatedBy:"."))
if ValueArray[1] == "0" {
displayResultLabel.text = "\(ValueArray[0])"
} else {
displayResultLabel.text = "\(newValue)"
}
stillTyping = false
}
}
#IBAction func numberPressed(_ sender: UIButton) {
let number = sender.currentTitle!
if stillTyping {
if (displayResultLabel.text?.characters.count)! < 20 {
displayResultLabel.text = displayResultLabel.text! + number
}
} else {
displayResultLabel.text = number
stillTyping = true
}
}
#IBAction func twoOperandsSignPressed(sender: UIButton) {
operationSign = sender.currentTitle!
firstOperand = currentInput
stillTyping = false
dotIsPlaced = false
}
func operateWithTwoOperands(operation: (Double, Double) -> Double) {
currentInput = operation(firstOperand, secondOperand)
stillTyping = false
}
#IBAction func equalitySignPressed(sender: UIButton) {
if stillTyping {
secondOperand = currentInput
}
dotIsPlaced = false
switch operationSign {
case "+":
operateWithTwoOperands{$0 + $1}
case "-":
operateWithTwoOperands{$0 - $1}
case "✕":
operateWithTwoOperands{$0 * $1}
case "÷":
operateWithTwoOperands{$0 / $1}
default: break
}
}
#IBAction func clearButtonPressed(_ sender: UIButton) {
firstOperand = 0
secondOperand = 0
currentInput = 0
displayResultLabel.text = "0"
dotIsPlaced = false
operationSign = ""
}
// +,-
#IBAction func plusMinusButtonPressed(_ sender: UIButton) {
currentInput = -currentInput
}
#IBAction func percentageButtonPressed(_ sender: UIButton) {
if firstOperand == 0 {
currentInput = currentInput / 100
} else {
secondOperand = firstOperand * currentInput / 100
}
}
#IBAction func squareRootButtonPressed(_ sender: UIButton) {
currentInput = sqrt(currentInput)
}
#IBAction func dotButtonPressed(_ sender: UIButton) {
if stillTyping && !dotIsPlaced {
displayResultLabel.text = displayResultLabel.text! + "."
dotIsPlaced = true
} else if !stillTyping && !dotIsPlaced {
displayResultLabel.text = "0."
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}
Too bad that $0 can be only Int, not Double.
You should to describe in-line functions in detail like following.
operateWithTwoOperands {first, second in return first / second;}
Thank you for reading.

How to remove "..." from my array?

In my calculator app I ran into a problem where I want ... to show in my array but only when the if statement for resultIsPending is true. Then after that I want the ... to be deleted. How can I do this in Swift? Here is the code of my ViewController.swift:
#IBOutlet weak var sequence: UILabel!
#IBOutlet weak var display: UILabel!
var userInTheMiddleOfTyping = false
var resultIsPending:Bool = false
var elements = [String]()
//var sequenceArray:Array = []
#IBAction func clear(_ sender: Any) {
display.text = " "
elements.removeAll()
elements = elements.filter{$0 != "\(String(describing: display.text))"}
sequence.text = elements.joined()
}
override func viewDidLoad() {
}
#IBAction func touchDigit(_ sender: UIButton) {
let digit = sender.currentTitle!
elements.append(digit)
combineToMakeOperationHistory()
if userInTheMiddleOfTyping{
let textCurrentlyInDisplay = display!.text!
display!.text = textCurrentlyInDisplay + digit
} else {
display!.text = digit
userInTheMiddleOfTyping = true
}
}
var displayValue: Double{
get{
return Double(display.text!)!
}
set{
display.text = String(newValue)
}
}
private var brain = CalculatorBrain()
#IBAction func performOperation(_ sender: UIButton) {
let perSender = sender.currentTitle!
elements.append(perSender)
combineToMakeOperationHistory()
if perSender == "+" || perSender == "÷" || perSender == "×" || perSender == "-" || perSender == "^"{
resultIsPending = true
}
if userInTheMiddleOfTyping{
brain.setOperand(displayValue)
userInTheMiddleOfTyping = false
}
userInTheMiddleOfTyping = false
if let mathematicalSymbol = sender.currentTitle{
brain.performOperation(mathematicalSymbol)
}
if brain.result != nil{
displayValue = brain.result!
}
}
func combineToMakeOperationHistory() {
if resultIsPending{ // this is the if statement
elements.append("...")
}else if resultIsPending == false{
}
sequence.text = elements.joined()
}
You can filter your elements array and remove the "...".
elements = elements.filter({ $0 != "..." })
Whenever you want to remove the occurrence of a String value.
you can uses something like hat
var resultIsPending:Bool = false{
didSet(isPending) {
if isPending {
elements.append("...")
} else {
elements.dropLast()
}
}
}
Don't combine data that are not of the same type. There is no reason to put ... into the array of elements:
func combineToMakeOperationHistory() {
var sequenceText: String = elements.joined()
if (resultIsPending) {
sequenceText += "..."
}
sequence.text = sequenceText
}
Since we are not appending ... to the array, we don't have to remove it.

Assigning in Swift a value but it thinks its nil

I am following the Stanford iOS Swift development course and have to make my displayValue an optional double, I assign a value to displayValue func performOperation but the getter for var displayValue: Double? reads it as nil, I have even hardcoded var displayValue: Double? to be 81 (example) but it is still read as nil, has anyone got any ideas? (I didn't want to post my whole code but if I've missed something out let me know!), thanks!
EDIT: here is my whole code now!
import UIKit
class ViewController: UIViewController {
var isThereApoint = true
var openStack = Array<Double?>()
var count = 0
#IBOutlet weak var history: UILabel!
#IBOutlet weak var calcView: UILabel!
var historyStack = Array<String>()
var userIsTyping = false
#IBAction func numberButton(sender: UIButton) {
let numberButton = sender.currentTitle!
if calcView.text!.rangeOfString("=") != nil{
calcView.text! = ""
}
if userIsTyping{
calcView.text! = calcView.text! + numberButton
}
else {
calcView.text! = numberButton
userIsTyping = true
}
}
#IBAction func decimalPoint(sender: AnyObject) {
if isThereApoint == true {
calcView.text! = calcView.text! + "."
isThereApoint = false
}
}
var displayValue: Double? {
get{
if NSNumberFormatter().numberFromString(calcView.text!) != nil{
return NSNumberFormatter().numberFromString(calcView.text!)!.doubleValue
}
else {
println("calc view in getter: \(calcView.text!)")
return 0
}
}
set{
calcView.text! = "\(newValue)"
userIsTyping = false
}
}
#IBAction func operate(sender: UIButton) {
let operation = sender.currentTitle!
switch operation{
case "×": performOperation ("×, ", {$0 * $1})
case "÷": performOperation ("÷, ",{$1 / $0})
case "+": performOperation ("+, ", {$0 + $1})
case "−": performOperation ("−, ", {$1 - $0})
case "√": performOperation ("√, ", {sqrt($0)})
case "Cos": performOperation ("Cos, ", {cos($0)})
case "Sin": performOperation("Sin, ", {sin($0)})
case "PI": displayValue! = M_PI
enter()
default: break
}
}
func performOperation(operatorSymbol: String, operation: (Double, Double) -> Double) {
if openStack.count >= 2 {
println("\(operatorSymbol)")
displayValue = operation(openStack.removeLast()!, openStack.removeLast()!)
println("display value : \(displayValue!)")
var displayAnswer = displayValue!
history.text! = history.text! + operatorSymbol
calcView.text! = "= \(displayAnswer)"
enter()
//calcView.text! = "= \(displayAnswer)"
}
}
#IBAction func positiveOrNegative(sender: AnyObject) {
if (calcView.text!.rangeOfString("-") != nil) {
calcView.text! = dropFirst(calcView.text!)
}
else {
calcView.text! = "-\(calcView.text!)"
}
}
func performOperation(operatorSymbol: String, operation: Double -> Double) {
if openStack.count >= 1 {
displayValue = operation(openStack.removeLast()!)
var displayAnswer = displayValue!
history.text! = history.text! + operatorSymbol
enter()
calcView.text! = "= \(displayAnswer)"
}
}
#IBAction func clearButton() {
history.text! = ""
for item in openStack{
openStack.removeLast()
}
calcView.text! = ""
}
#IBAction func backspace(sender: AnyObject) {
if countElements(calcView.text!) > 0 {
calcView.text! = dropLast(calcView.text!)
}
}
#IBAction func enter() {
isThereApoint = true
if history.text! == "History"{
history.text! = ""
}
openStack.append(displayValue!)
var userIsTyping = false
println("openStack = \(openStack)")
history.text! = history.text! + "\(displayValue!)" + ", "
calcView.text! = ""
}
}
Your problem is that you are setting calcView.text to "Optional(81.0)". You need to unwrap the Double? that is in newValue inside of set for displayValue:
set {
calcView.text = "\(newValue!)"
userIsTyping = false
}
Because the displayValue was "Optional(81.0)", NSNumberFormatter couldn't convert the value, so it returns nil.

Resources