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.
Related
My problem is that I can click and input multiple numbers for my first value but then after I used a math operator (ex. +,-,*,/) it only allows me to input a single value unlike the first time running it.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var Label: UILabel!
var secondNumber: Double = 0;
var firstNumber: Double = 0;
var performingMath = false
var operatorUsed = 0;
#IBAction func cleartext(_ sender: UIButton) {
Label.text = ""
performingMath = false
}
#IBAction func Numbers(_ sender: UIButton) {
if performingMath {
Label.text = String(sender.tag - 1)
secondNumber = Double(Label.text!)!
performingMath = true
} else {
Label.text = Label.text! + String(sender.tag - 1)
secondNumber = Double(Label.text!)!
}
}
#IBAction func Operators(_ sender: UIButton) {
if Label.text != " " && sender.tag != 11 {
firstNumber = Double(Label.text!)!
if sender.tag == 12 {
Label.text = "+"
} else if sender.tag == 13 {
Label.text = "-"
} else if sender.tag == 14 {
Label.text = "*"
} else if sender.tag == 15 {
Label.text = "/"
}
operatorUsed = sender.tag
performingMath = true
} else if sender.tag == 11 {
if operatorUsed == 12 {
Label.text = String(firstNumber + secondNumber)
}
if operatorUsed == 13 {
Label.text = String(firstNumber - secondNumber)
}
if operatorUsed == 14 {
Label.text = String(firstNumber * secondNumber)
}
if operatorUsed == 15 {
Label.text = String(firstNumber / secondNumber)
}
}
}
}
I expect the that I can input many values as possible after I used a math operator (ex. +-*/)
When you update the label's text when performingMath is true, you just assign the new value instead of adding the value to the existing one (see line 3)
#IBAction func Numbers(_ sender: UIButton) {
if performingMath {
Label.text = String(sender.tag - 1) // !! HERE !!
secondNumber = Double(Label.text!)!
performingMath = true
} else {
Label.text = Label.text! + String(sender.tag - 1)
secondNumber = Double(Label.text!)!
}
}
This should perform the same action as when performingMath is false, so you just need to update this line with:
Label.text = Label.text! + String(sender.tag - 1)
I have recently, after many errors, finished my first application (its a calculator) I learned that it is usually not wise to have any calculations be performed inside the ViewController but for it to instead be completed in a seperate file. My main question is:
Is is possible to place my current code inside each of my functions into a class in swift that will perform them instead?
Then I could just implement class.function() under each function in the view controller.
The reason why I want to do this is so for the future I can just have a calculator class, and I will also know how to do this with every future project and I will be able to use those classes as well.
I have tried experimenting but i cannot seem to reference the lbl.output in my other files.
//
// 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 {
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
#IBOutlet weak var LBLOutput: UILabel!
#IBAction func btrNumberClick(_ sender: UIButton) {
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 calculate() -> Double {
let firstNumber = Double(num1)!
let secondNumber = Double(num2)!
num1 = ""
num2 = ""
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
}
}
#IBAction func clearTheLabel(_ sender: Any) {
num1 = ""
num2 = ""
LBLOutput.text = "0"
isClear = true
}
#IBAction func goNegative(_ sender: Any){
var negativeChecker = Double(num1)!
if negativeChecker > 0
{ num1 = ("-" + num1)
LBLOutput.text = num1
}else{
negativeChecker = (-2 * negativeChecker) + negativeChecker
num1 = String(negativeChecker)
LBLOutput.text = String(negativeChecker)
}
}
#IBAction func squareRoot(_ sender: Any) {
let squareRootX = sqrt(Double(LBLOutput.text!)!)
num1 = String(squareRootX)
LBLOutput.text = String(squareRootX)
}
}
Rather than trying to call LBLOutput.text = x from your "brain" class, just have the brain functions return the correct value of your calculation, and use your viewController to set that as the text in your labels. That is the intended use for a viewController if you are following "MVC".
For example, if your Brain class has a function called sum you could set it up like so:
class func sum(x: Int, y: Int) -> Int {
return x + y
}
and in your viewController you can just say LBLOutput.text = "\(Brain.sum(x, y: y)"
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
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.
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.