Add a history on calculator (iOS) - ios

I'm having a problem adding a history to calculator (lblHistory Label)
I want to store my previous inputs in the lblHistory : UILabel
but all it did is store the first number and its operation.
Is there any algorithm that you will store all previous inputs of your calculator?
This is my class MyCalculator.swift
Class MyCalculator
//
// MyCalculator.swift
// Calculator
//
// Created by
// abcdefgh
//
import Foundation
class MyCalculator
{
var memory: Float = 0
var percentnum: Float = 0
var currentNum: Float = 0
var result: Float = 0
var operation: String = ""
var isOperation: Bool = false
var isRepeatOperation: Bool = false
var isNum: Bool = false
func operation (operation:String) -> Float
{
if operation == "+" {
result = result + currentNum
}
else if operation == "-" {
result = result - currentNum
}
else if operation == "*" {
result = result * currentNum
}
else if operation == "/" {
result = result / currentNum
}
return result
}
func percent(percentNum:Float) ->Float
{
let valpercent = percentNum * 0.01
result = result * valpercent
return result
}
func clearAll() {
result = 0
currentNum = 0
isNum = false
}
}
and this is the view controller of my calculator.
View Controller
/ ViewController.swift
// Calculator
//
// Created by
// abcdefgh
//
import UIKit
class ViewController: UIViewController {
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.
}
//Start Calculator
//Label History: This is where the history is displayed
#IBOutlet weak var lblHistory: UILabel!
//Label Result: This is where the result is displayed
#IBOutlet weak var lblResult: UILabel!
//Initialization
let calc = MyCalculator() //call the class MyCalculator
//Function for Number Inputs
#IBAction func btnNumInput(sender: AnyObject)
{
let num = sender.currentTitle
if calc.isNum == false
{
lblResult.text = num
calc.isNum = true
}
else
{
lblResult.text = lblResult.text! + num!!
}
calc.isRepeatOperation = false
lblResult.adjustsFontSizeToFitWidth = true
}
//Function for Operations
#IBAction func btnOperations(sender: AnyObject)
{
calc.isNum = false
if calc.isOperation && !calc.isRepeatOperation
{
calc.currentNum = Float(lblResult.text!)!
if calc.operation == "+"
{
calc.result = calc.operation("+")
}
else if calc.operation == "-"
{
calc.result = calc.operation("-")
}
else if calc.operation == "*"
{
calc.result = calc.operation("*")
}
else if calc.operation == "/"
{
calc.result = calc.operation("/")
}
if calc.operation == "/" && calc.currentNum == 0
{
lblResult.text = "Cannot divide by zero"
lblResult.adjustsFontSizeToFitWidth = true
}
else
{
let stringresult = String(format:"%g" , calc.result)
lblResult.text = "\(stringresult)"
calc.isOperation = false
}
}
else
{
calc.result = Float(lblResult.text!)!
}
let strresult = String(format:"%g", calc.result)
calc.operation = sender.currentTitle!!
lblHistory.text = strresult + calc.operation
calc.isOperation = true
calc.isRepeatOperation = true
}
From this code here:
let strresult = String(format:"%g", calc.result)
calc.operation = sender.currentTitle!!
lblHistory.text = strresult + calc.operation
this should store any input from the history label but it will only store the first input and its operator.
The result:
2+2 =4 //this is the input variables and operation
//the result is 4 and display on lblResult: UILabel
2+ // the "2+" is only stored in lblHistory: UILabel not the whole input itself

Related

Swift 4 - Quiz App Random Questions

I'm a beginner to Swift and generally Xcode. Thank you in advance for your time and help :)
I am doing a Quiz App, and I try to have random questions... I have a function to generate random numbers that I tried to apply in viewDidLoad()... unfortunately I can not guess how to use that information in his variable "var currentQuestion = 0"
This is the code:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
generateRandomNumber(0, 9, 10)
}
override func viewDidAppear(_ animated: Bool) {
newQuestion()
}
// Quiz//
let questions = ["Q1","Q2","Q3","Q4","Q5"]
let answers = [["A","2","3"],["B","2","3"],["C","2","3"],["D","2","3"],["E","2","3"]]
//Variables
var currentQuestion = 0
var rightAnswerPlacement:UInt32 = 0
//Generate Random Numbers
func generateRandomNumber(_ from:Int, _ to:Int, _ qut:Int?) -> [Int] {
var myRandomNumbers = [Int]() //All our generated numbers
var numberOfNumbers = qut //How many numbers to generate
let lower = UInt32(from) //Generate from this number..
let higher = UInt32(to+1) //To this one
if numberOfNumbers == nil || numberOfNumbers! > (to-from) + 1 {
numberOfNumbers = (to-from) + 1
}
while myRandomNumbers.count != numberOfNumbers {
let myNumber = arc4random_uniform(higher - lower) + lower
if !myRandomNumbers.contains(Int(myNumber)) {
myRandomNumbers.append(Int(myNumber))
}
}
return myRandomNumbers
}
//Label
#IBOutlet weak var lbl: UILabel!
//Button
#IBAction func action(_ sender: AnyObject) {
if (sender.tag == Int(rightAnswerPlacement)) {
print ("RIGHT!")
} else {
print ("WRONG!!!!!!")
}
if (currentQuestion != questions.count) {
newQuestion()
} else {
}
}
//Function that displays new question
func newQuestion() {
lbl.text = questions[currentQuestion]
rightAnswerPlacement = arc4random_uniform(3)+1
//Create a button
var button:UIButton = UIButton()
var x = 1
for i in 1...3 {
//Create a button
button = view.viewWithTag(i) as! UIButton
if (i == Int(rightAnswerPlacement)) {
button.setTitle(answers[currentQuestion][0], for: .normal)
} else {
button.setTitle(answers[currentQuestion][x], for: .normal)
x = 2
}
}
currentQuestion += 1
}
Any idea that how will be possible to resolve?
First you need to store the array of random questions that you generate (side note you appear to try to generate 10 random numbers but have only 5 questions).
Then instead of using the currentQuestion directly you use that to access the question in the array.
So change it to this:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
questionArray = generateRandomNumber(0, 9, 10)
}
override func viewDidAppear(_ animated: Bool) {
newQuestion()
}
// Quiz//
let questions = ["Q1","Q2","Q3","Q4","Q5"]
let answers = [["A","2","3"],["B","2","3"],["C","2","3"],["D","2","3"],["E","2","3"]]
//Variables
var currentQuestion = 0
var rightAnswerPlacement:UInt32 = 0
var questionArray: [Int] = [] // Just an initial value
//Generate Random Numbers
func generateRandomNumber(_ from:Int, _ to:Int, _ qut:Int?) -> [Int] {
var myRandomNumbers = [Int]() //All our generated numbers
var numberOfNumbers = qut //How many numbers to generate
let lower = UInt32(from) //Generate from this number..
let higher = UInt32(to+1) //To this one
if numberOfNumbers == nil || numberOfNumbers! > (to-from) + 1 {
numberOfNumbers = (to-from) + 1
}
while myRandomNumbers.count != numberOfNumbers {
let myNumber = arc4random_uniform(higher - lower) + lower
if !myRandomNumbers.contains(Int(myNumber)) {
myRandomNumbers.append(Int(myNumber))
}
}
return myRandomNumbers
}
//Label
#IBOutlet weak var lbl: UILabel!
//Button
#IBAction func action(_ sender: AnyObject) {
if (sender.tag == Int(rightAnswerPlacement)) {
print ("RIGHT!")
} else {
print ("WRONG!!!!!!")
}
if (currentQuestion != questions.count) {
newQuestion()
} else {
}
}
//Function that displays new question
func newQuestion() {
lbl.text = questions[questionArray[currentQuestion]]
rightAnswerPlacement = arc4random_uniform(3)+1
//Create a button
var button:UIButton = UIButton()
var x = 1
for i in 1...3 {
//Create a button
button = view.viewWithTag(i) as! UIButton
if (i == Int(rightAnswerPlacement)) {
button.setTitle(answers[questionArray[currentQuestion]][0], for: .normal)
} else {
button.setTitle(answers[questionArray[currentQuestion]][x], for: .normal)
x = 2
}
}
currentQuestion += 1
}
(I think the code is correct but I'm currently running some tests in Xcode so can't check. If there is a problem leave a comment.)

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.

Creating a class that does all of the functions of the viewcontroller

I am attempting to make my calculator function look more organized. I have decided to create a calculator class that does all of the functions. Currently this is not working, my only problem is that I make a new instance of a class every time a number is pressed, this happens because I dont know what number is going to be pressed next so I cannot define LBLOutput in my constructor until It is passed to me. Here are my two files
The problem lies where I am calling the cb.functions. Currently they work but only one number can show up on the screen at a time due to the fact that a new class is declared every time.
Is this a viable way of making the calculator? Do i need to just start from scratch?
//
// ViewController.swift
// MyCalculator
//
// Created by Kevin Maldjian on 2/6/17.
// Copyright © 2017 Kevin Maldjian. All rights reserved.
//
import UIKit
import Foundation
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBOutlet weak var LBLOutput: UILabel!
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func btrNumberClick(_ sender: UIButton) {
let cb = calculatorBrain(LBLOutput: LBLOutput , sender: sender)
cb.btrNumberClick()
}
#IBAction func clearTheLabel(_ sender: Any) {
let cb = calculatorBrain(LBLOutput: LBLOutput, sender: sender as! UIButton)
cb.clearTheLabel()
}
#IBAction func goNegative(_ sender: Any){
let cb = calculatorBrain(LBLOutput: LBLOutput, sender: sender as! UIButton)
cb.goNegative()
}
#IBAction func squareRoot(_ sender: Any) {
let cb = calculatorBrain(LBLOutput: LBLOutput, sender: sender as! UIButton)
cb.squareRoot()
}
}
THE MAIN FUNCTIONS ARE DONE HERE
//
// calculatorBrain.swift
// SalvageAttempt
//
// Created by Kevin Maldjian on 3/13/17.
// Copyright © 2017 Kevin Maldjian. All rights reserved.
//
import Foundation
import UIKit
class calculatorBrain
{
var num1 = ""
var num2 = ""
var finalString = ""
var isFirstNumber = true
var safeToAdd = true
var hasFinalString = false
var isClear = true
var hasDecimal = false
var doubleChecker = 0
var hasSecondDecimal = false
var LBLOutput = UILabel()
var sender = UIButton()
init(LBLOutput : UILabel, sender : UIButton) {
self.num1 = " "
self.num2 = " "
self.finalString = ""
self.isFirstNumber = true
self.safeToAdd = true
self.hasFinalString = false
self.isClear = true
self.hasDecimal = false
self.doubleChecker = 0
self.hasSecondDecimal = false
self.LBLOutput = LBLOutput
self.sender = sender
}
func btrNumberClick() {
if isClear {
LBLOutput.text = ""
isClear = false
}
let currentText = LBLOutput.text!
let textLabel = sender.titleLabel?.text
if let text = textLabel {
switch text {
case "+", "x", "/", "-","%":
if hasFinalString {
return
}
finalString = text
isFirstNumber = false
hasFinalString = true
safeToAdd = true
LBLOutput.text = "\(currentText) \(finalString) "
break
case "=":
if !hasFinalString
{break}
isFirstNumber = true
hasFinalString = false
isClear = true
var result = calculate()
if result.truncatingRemainder(dividingBy:1) == 0
{
result = (result)
}
LBLOutput.text = "\(result)"
num1 = "\(result)"
safeToAdd = false
hasSecondDecimal = false
hasDecimal = false
break
case ".":
if !safeToAdd{
num1 = ""
LBLOutput.text = ""
num1 = "\(num1)\(text)"
LBLOutput.text = LBLOutput.text! + num1
safeToAdd = true
} else if isFirstNumber{
if hasDecimal
{break}
LBLOutput.text = ""
num1 = "\(num1)\(text)"
LBLOutput.text = LBLOutput.text! + num1
hasDecimal = true
}else{
if hasSecondDecimal
{break}
num2 = "\(num2)\(text)"
LBLOutput.text = "\(currentText)\(text)"
hasSecondDecimal = true
}
break
default:
if !safeToAdd{
num1 = ""
LBLOutput.text = ""
num1 = "\(num1)\(text)"
LBLOutput.text = LBLOutput.text! + num1
safeToAdd = true
} else if isFirstNumber{
LBLOutput.text = ""
num1 = "\(num1)\(text)"
LBLOutput.text = LBLOutput.text! + num1
}else{ num2 = "\(num2)\(text)"
LBLOutput.text = "\(currentText)\(text)"
}
break;
}
}
}
func goNegative(){
var negativeChecker = Double(num1)!
if negativeChecker > 0
{ num1 = ("-" + num1)
LBLOutput.text = num1
}else{
negativeChecker = (-2 * negativeChecker) + negativeChecker
num1 = String(negativeChecker)
LBLOutput.text = String(negativeChecker)
}
}
func squareRoot() {
let squareRootX = sqrt(Double(LBLOutput.text!)!)
num1 = String(squareRootX)
LBLOutput.text = String(squareRootX)
}
#IBAction func clearTheLabel() {
num1 = ""
num2 = ""
LBLOutput.text = "0"
isClear = true
}
func calculate() -> Double {
let firstNumber = Double(self.num1)!
let secondNumber = Double(self.num2)!
num1 = ""
num2 = ""
self.isClear = false
switch finalString {
case "+":
return firstNumber + secondNumber
case "-":
return firstNumber - secondNumber
case "x":
return firstNumber * secondNumber
case "/":
return firstNumber / secondNumber
case "%":
return (firstNumber * 100) / secondNumber
default:
return 0
}
}
}
Move all of your functions out of this class called "calculatorBrain". Just make them public, or in the case of a separate target (like a Framework) open. For instance:
class MyVC:UIViewController {
let a:Float = 1.0
let b:Float = 1.0
let currentSum = sum(a,b)
print(currentSum) // displays 2.0
}
In a separate file:
public sum(var1:Float, var2:Float) {
return var1+var2
}
Not much more to it. Again, remove everything from a class and you won't need an instance.

Class "View controller" has no initializers

I got an "Class "View controller" has no initializers" error.
I tried to initialize all variables but the error keeps appearing.
Hear is the code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var Screen: UILabel!
var primerNum = Float()
var segundoNum = Float()
var result = Float()
var operat = ""
var isTypingNumber = false
var num: Int?
var coma: Int?
#IBAction func num(sender: AnyObject) {
var num = sender.currentTitle
if isTypingNumber == true {
Screen.text = Screen.text! + num!!
} else {
Screen.text = num
}
isTypingNumber = true
}
#IBAction func coma(sender: AnyObject) {
var coma = sender.currentTitle
Screen.text = Screen.text! + coma!!
}
#IBAction func operat(sender: AnyObject) {
operat = sender.currentTitle!!
primerNum = (Screen.text! as NSString).floatValue
}
#IBAction func igual(sender: AnyObject) {
segundoNum = (Screen.text! as NSString).floatValue
if operat == "+" {
result = primerNum + segundoNum
} else if operat == "-" {
result = primerNum - segundoNum
} else if operat == "x" {
result = primerNum * segundoNum
} else if operat == "/" {
result = primerNum / segundoNum
} else if operat == "%" {
result = (primerNum * segundoNum) / 100
}
Screen.text = "\(result)"
}
#IBAction func clear(sender: AnyObject) {
primerNum = 0
segundoNum = 0
result = 0
Screen.text = "\(result)"
}
}
Thank you in advance!!
That looks correct, and also compiles fine for me locally. Did you try Cleaning and rebuilding (command-shift-K, then command-b)? Alternatively, restart Xcode.

How to code a calculator that adds, numbers consecutively (Swift)

This is my code for the calculator, right now I can only add 2 numbers consecutively before hitting the equals sign, I want to make where I can add More than two Numbers before hitting the equals button. (Written in Swift)
import UIKit
class CalcControl: UIView {
var firstEntry = ""
var isUserInMiddleOfTypingNumbers:Bool?
var didUserPressedOperation:Bool?
var op:String?
#IBOutlet var displayLabel: UILabel!
#IBAction func digitPressed(sender: UIButton) {
if (didUserPressedOperation == nil) {
//displayLabel.text = ""
didUserPressedOperation = nil
}
if (isUserInMiddleOfTypingNumbers == nil) {
displayLabel.text = displayLabel.text! + sender.currentTitle!
} else {
displayLabel.text = sender.currentTitle
isUserInMiddleOfTypingNumbers = true
}
}
#IBAction func operationPressed(sender: UIButton) {
op = sender.currentTitle
firstEntry = displayLabel.text!
didUserPressedOperation = true
displayLabel.text = ""
}
#IBAction func clearPressed(sender: UIButton) {
self.clear()
}
func clear() {
firstEntry = ""
isUserInMiddleOfTypingNumbers = nil
didUserPressedOperation = nil
displayLabel.text = ""
}
#IBAction func equalPressed(sender: UIButton) {
var secondEntry:NSString = displayLabel.text!
println((firstEntry))
println((secondEntry))
if(op == "+") {
displayLabel.text = (((firstEntry as NSString!).doubleValue + (secondEntry as NSString).doubleValue) as NSNumber).stringValue
} else if(op == "-") {
displayLabel.text = (((firstEntry as NSString!).doubleValue - (secondEntry as NSString).doubleValue) as NSNumber).stringValue
} else if(op == "x") {
displayLabel.text = (((firstEntry as NSString!).doubleValue * (secondEntry as NSString).doubleValue) as NSNumber).stringValue
} else if(op == "/") {
displayLabel.text = (((firstEntry as NSString!).doubleValue / (secondEntry as NSString).doubleValue) as NSNumber).stringValue
}
firstEntry = ""
isUserInMiddleOfTypingNumbers = nil
didUserPressedOperation = nil
}
}
I would adjust your logic so that:
There is an IB Action that all the operator keys (+, -, x, /) are tied to. In this IB Action any time it is activated, there are two choices: a) prepare for another number to be entered or b) the previous key sequence was a number followed by an operator symbol and the button is the same as an Enter.
An IB Action for the delete key. Obvious role.
An IB Action for the Enter key.

Resources