go back and forth a string-array with two buttons - swift

I want to show the first item on viewdidload() and then have the user go to the next item in the array and have the option to go back and disable the back button if it’s the first index and disable the button if its the last index. Here is my code
#IBAction func back(_ sender: Any) {
c -= 1
if c == thkrArray.count{
nextButton.isEnabled = false
}
if c == 0{
backButton.isEnabled = false
}
let thkr: String = thkrArray[c]
Text1.text = thkr
}
#IBAction func A2(_ sender: Any) {
c += 1
if c == thkrArray.count{
nextButton.isEnabled = false
}
if c == 0 {
backButton.isEnabled = false
}
if c > 0{
backButton.isEnabled = false
}
let thkr: String = thkrArray[c]
Text1.text = thkr
}

The easiest way to achieve this is to add an observer to c:
var c: Int = 0 {
didSet {
Text1.text = thkrArray[c]
backButton.isEnabled = c > 0
nextButton.isEnabled = c < thkrArray.count - 1
}
}
#IBAction func back(_ sender: Any) {
c -= 1
}
#IBAction func A2(_ sender: Any) { // isn't this `next`?
c += 1
}
override func viewDidLoad() {
super.viewDidLoad()
c = 0
}

Related

How to refer #IBAction Func to several button outlets

I have lots of buttons that when pressed run very similar code, im currently writing a function for each, is there a way to compact this to one function?
Heres some of the code:
#IBAction func b0(_ sender: UIButton) {
if pressedArray[0] && buttonsCanBePressed {
pressedArray[0] = false
b0.backgroundColor = notPressedColour
} else if buttonsCanBePressed {
b0.backgroundColor = pressedColour
pressedArray[0] = true
}
}
#IBAction func b1(_ sender: UIButton) {
if pressedArray[1] && buttonsCanBePressed {
pressedArray[1] = false
b1.backgroundColor = notPressedColour
} else if buttonsCanBePressed {
b1.backgroundColor = pressedColour
pressedArray[1] = true
}
}
#IBAction func b2(_ sender: UIButton) {
if pressedArray[2] && buttonsCanBePressed {
pressedArray[2] = false
b2.backgroundColor = notPressedColour
} else if buttonsCanBePressed {
b2.backgroundColor = pressedColour
pressedArray[2] = true
}
}
Yes, You can make only one IBAction function, and then drag the circle in the line number to all the buttons you want, and you can differentiate the buttons using sender.tag

Swift - Automatic Caluclation

I am currently building a calculator app with swift.
I want the calculation to be automatic instead of me pressing = button.
EQLabel is where i want the calculation to be
and inputLabel is where the user can see there equation for example 1 + 5
Below is my calculator code.
// Start of Calculator
#IBOutlet weak var EQLabel: UITextField!
#IBOutlet weak var inputLabel: UITextField!
var numberOnScreen = 0;
var previousNumber = 0;
var performingMath = false
var operation = 0;
#IBAction func numbers(_ sender: UIButton) {
if performingMath == true {
inputLabel.text = String(sender.tag-1)
numberOnScreen = Int(Double(inputLabel.text!)!)
performingMath = false
}
else {
inputLabel.text = String(sender.tag-1)
numberOnScreen = Int(Double(inputLabel.text!)!)
}
}
#IBAction func multiButtons(_ sender: UIButton) {
if inputLabel.text != "" && sender.tag != 15 {
previousNumber = Int(Double(inputLabel.text!)!)
// Plus
if sender.tag == 11 {
inputLabel.text! = "+"
}
// Times
if sender.tag == 12 {
inputLabel.text = "x"
}
// Minus
if sender.tag == 13 {
inputLabel.text = "-"
}
// Divide
if sender.tag == 14 {
inputLabel.text = "/"
}
operation = sender.tag
performingMath = true
}
else if sender.tag == 15 {
if operation == 11 {
EQLabel.text = String(previousNumber + numberOnScreen)
}
if operation == 12 {
EQLabel.text = String(previousNumber * numberOnScreen)
}
if operation == 13 {
EQLabel.text = String(previousNumber - numberOnScreen)
}
if operation == 14 {
EQLabel.text = String(previousNumber / numberOnScreen)
}
}
}
Hope this helps. Should do exactly what you want.
override func viewDidLoad() {
yourTextField.addTarget(self, action: #selector(self.calculateTotal(_:)), forControlEvents: UIControlEvents.EditingChanged)
}
func calculateTotal() {
let totalInt = Int(firstTextField.text!) + Int(secondTextField.text!)
totalLabel.text = String(totalInt)
}
Do let me know if you have any doubts.
Try using addTarget on your button. But your calculator needs to know when you have finished typing in the second number, unless you are only using numbers of a certain length?. If you want it to update the answer as you type id go with something like.
inputLabel.addTarget(self, action: #selector(yourCaculateMethod), for: .editingChanged)
then have your equalsLabel.text equal the result. this will update it as you go.
Id think about naming your inputLabel to inputTextField too as its a little missleading

maximum/minimum on incrementing buttons

I'm fairly new to Xcode/Swift and am wondering how to set a maximum and minimum for amounts that result in a plus and minus button being touched. My existing code is below. The notifyBeforeAvailabilty I want to go from 1-20 and the ratePerMinute I want to go from $0.00 to $15.00.
var notifyBeforeAvailability: Int!
var ratePerMin: Float!
notifyBeforeAvailability = 1
updateNotifyBeforeAvailability()
ratePerMin = 0.10
updateRatePerMin()
#IBAction func notifyBeforeAvailabilityPlus(sender: AnyObject) {
notifyBeforeAvailability = notifyBeforeAvailability + 1
updateNotifyBeforeAvailability()
}
#IBAction func notifyBeforeAvailabilityMinus(sender: AnyObject) {
notifyBeforeAvailability = notifyBeforeAvailability - 1
updateNotifyBeforeAvailability()
}
func updateNotifyBeforeAvailability() {
lblNotifyTime.text = String(notifyBeforeAvailability) + "min"
}
#IBAction func ratePerMinPlus(sender: AnyObject) {
ratePerMin = ratePerMin + 0.10
updateRatePerMin()
}
#IBAction func ratePerMinMinus(sender: AnyObject) {
ratePerMin = ratePerMin - 0.10
updateRatePerMin()
}
func updateRatePerMin() {
let currentValue = ratePerMin
let current_string = String.localizedStringWithFormat("%.2f", currentValue)
lblYourRate.text = "$" + current_string
}
You can use min & max for clamping values. Something like:
notifyBeforeAvailability = min(max(1, notifyBeforeAvailability + 1), 20)
// In this example 1 & 20 are your bounds
// set the others accordingly...
Also, you could avoid to format numbers yourself by utilizing NSNumberFormatter
By the way... In case you're using UIStepper controls, there are minimumValue & maximumValue (along with a stepValue) properties that handle limits for you...
The Alladinian's answer is right, but I prefer use didSet in var and from there call the functions.
var notifyBeforeAvailability : Int = 1 {
didSet {
if oldValue < 1 {
self.notifyBeforeAvailability = 1
}
if oldValue > 20 {
self.notifyBeforeAvailability = 20
}
updateNotifyBeforeAvailability()
}
}
var ratePerMin : Float = 0.10 {
didSet{
if newValue < 0.0{
self.ratePerMin = 0.0
}
if newValue > 15.0 {
self.ratePerMin = 15.0
}
print(newValue)
updateRatePerMin()
}
}
#IBAction func notifyBeforeAvailabilityPlus(sender: AnyObject) {
notifyBeforeAvailability += 1
}
#IBAction func notifyBeforeAvailabilityMinus(sender: AnyObject) {
notifyBeforeAvailability -= 1
}
func updateNotifyBeforeAvailability() {
lblNotifyTime.text = String(notifyBeforeAvailability) + "min"
}
#IBAction func ratePerMinPlus(sender: AnyObject) {
ratePerMin += 0.10
}
#IBAction func ratePerMinMinus(sender: AnyObject) {
ratePerMin -= 0.10
}
func updateRatePerMin() {
let currentValue = ratePerMin
let current_string = String.localizedStringWithFormat("%.2f", currentValue)
lblYourRate.text = "$" + current_string
}

I need help debugging this error - Maths Quiz for Kids

My school project is a children's maths game where it test them in addition, subtraction and multiplication. I have two VC's that are linked to the error. The error I keep having is that every time I choose any of the options it ignores all the other operations and follows the instructions for multiplication! I have tried everything and I'm getting frustrated with this application.
Option_VC
class Option_VC: UIViewController {
var addition_true: Bool = false
var subtract_true: Bool = false
var multiply_true: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if addition_true == true {
let nextVC: Quiz_VC = segue.destinationViewController as! Quiz_VC
nextVC.addition_true = true
}else if subtract_true == true {
let nextVC: Quiz_VC = segue.destinationViewController as! Quiz_VC
nextVC.subtract_true = true
}else {
let nextVC: Quiz_VC = segue.destinationViewController as! Quiz_VC
nextVC.multiply_true = true
}
}
#IBAction func addition_enter(sender: AnyObject) {
addition_true = true
multiply_true = false
subtract_true = false
}
#IBAction func subtract_enter(sender: AnyObject) {
subtract_true = true
addition_true = false
multiply_true = false
}
#IBAction func multiply_enter(sender: AnyObject) {
multiply_true = true
addition_true = false
subtract_true = false
}
}
Quiz_VC
class Quiz_VC: UIViewController {
#IBOutlet var n1_lbl: UILabel!
#IBOutlet var back: UIButton!
#IBOutlet var next: UIButton!
#IBOutlet var enter: UIButton!
#IBOutlet var answer_field: UITextField!
#IBOutlet var symbol_lbl: UILabel!
#IBOutlet var n2_lbl: UILabel!
#IBOutlet var comment_lbl: UILabel!
#IBOutlet var score_lbl: UILabel!
var addition_true: Bool = false
var subtract_true: Bool = false
var multiply_true: Bool = false
var enter_entered_true: Bool = false
var answer: UInt32 = 0
var finalanswer: UInt32 = 0
var n1: UInt32 = 0
var n2: UInt32 = 0
var count = 0
var score = 0
var temp: UInt32 = 0
var operation: String = ""
override func viewDidLoad() {
super.viewDidLoad()
back.hidden = true
next.hidden = true
if addition_true == true {
AdditionQuestions()
}else if subtract_true == true {
SubtractionQuestions()
}
if multiply_true == true && addition_true == false && subtract_true == false{
MultiplicationQuestions()
}
}
func Operation() {
if addition_true == true {
operation = "1"
}else if subtract_true == true {
operation = "2"
}else {
operation = "3"
}
switch operation {
case "1":
finalanswer = n1 + n2
case "2":
finalanswer = n1 - n2
case "3":
finalanswer = n1 * n2
default: break
}
}
func AdditionQuestions() {
n1 = arc4random_uniform(9)+1
n2 = arc4random_uniform(9)+1
n1_lbl.text = "\(n1)"
n2_lbl.text = "\(n2)"
symbol_lbl.text = "+"
score_lbl.text = ""
comment_lbl.text = ""
}
func SubtractionQuestions() {
n1 = arc4random_uniform(9)+1
n2 = arc4random_uniform(9)+1
symbol_lbl.text = "-"
if n2 > n1 {
temp = n1
n1 = n2
n2 = temp
}
n1_lbl.text = "\(n1)"
n2_lbl.text = "\(n2)"
}
func MultiplicationQuestions() {
n1 = arc4random_uniform(9)+1
n2 = arc4random_uniform(9)+1
symbol_lbl.text = "×"
n1_lbl.text = "\(n1)"
n2_lbl.text = "\(n2)"
}
func EndQuiz() {
if count > 3 {
enter.hidden = true
next.hidden = true
back.hidden = false
score_lbl.text = "Score: \(score)"
comment_lbl.text = "Completed Quiz"
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func enter_entered(sender: AnyObject) {
if answer_field.text != nil {
enter_entered_true = true
answer = UInt32(answer_field.text!)!
count = count + 1
Operation()
if answer != finalanswer {
comment_lbl.text = "Incorrect"
} else {
comment_lbl.text = "Correct"
score = score + 1
}
} else {
comment_lbl.text = "Enter a number!"
}
enter.hidden = true
next.hidden = false
}
#IBAction func next_entered(sender: AnyObject) {
if addition_true == true {
AdditionQuestions()
comment_lbl.text = ""
}else if subtract_true == true {
SubtractionQuestions()
comment_lbl.text = ""
}
if multiply_true == true && addition_true == false && subtract_true == false{
MultiplicationQuestions()
comment_lbl.text = ""
}
enter.hidden = false
next.hidden = true
EndQuiz()
}
}
When you hit one of the buttons (Add, Subtract or Multiply) then the application immediately performs prepareForSegue before it performs the action associated with those buttons. Therefore addition_true, subtraction_true and multiplication_true are all always false and the code falls through to the else clause which sets the multiplication option.
To get around this:
In the storyboard remove the segues from the three buttons.
Add a segue from the first view controller to the second one (control drag from the yellow circle at the top of the first view controller to the body of the second view controller).
Give the segue a name(highlight the segue and name it ("mainSegue" or something) in the Attributes Inspector)
In your code add the following line to the end of each of the three actions (addition_enter, etc.):
performSegueWithIdentifier("mainSegue", sender: self)
This will ensure that the segue is called after the button actions have been performed.
In your Quiz_VC class update viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
back.hidden = true
next.hidden = true
if addition_true == true {
AdditionQuestions()
}else if subtract_true == true {
SubtractionQuestions()
}else if multiply_true == true{
MultiplicationQuestions()
}
}
and
func Operation() {
if addition_true == true {
operation = "1"
}else if subtract_true == true {
operation = "2"
}else if multiply_true == true {
operation = "3"
}
switch operation {
case "1":
finalanswer = n1 + n2
case "2":
finalanswer = n1 - n2
case "3":
finalanswer = n1 * n2
default: break
}
}
also
#IBAction func next_entered(sender: AnyObject) {
if addition_true == true {
AdditionQuestions()
comment_lbl.text = ""
}else if subtract_true == true {
SubtractionQuestions()
comment_lbl.text = ""
}else if multiply_true == true{
MultiplicationQuestions()
comment_lbl.text = ""
}else{
enter.hidden = false
next.hidden = true
EndQuiz()
}
}
I think that your #IBAction functions are not hooked up, or are not getting called because the button is linked to a segue.
This means that all of the Bools are false in prepareForSegue. And the logic in that function sets up the QuizVC for multiplication in that case (the last else clause does not have an if qualifier).
So, keep the segues in the storyboard. Populate the segue identifier string in the object inspector (the panel on the right in Xcode). Use, say, ADDITION_SEGUE, MULTIPLY_SEGUE, SUBTRACTION_SEGUE. You don't have to use caps and underscores, that's just my habit.
Then in prepareForSegue: you can tell which segue triggered the action. Set the properties on the QuizVC on the basis of that. Then you don't need those Bools at all in OptionVC.
In prepareForSegue:
if segue.identifier == "ADDITION_SEGUE" {
destinationViewController...
}
How about also putting an enum into QuizVC rather than using the Bools:
enum QuizType {
case Addition, Subtraction, Multiplication
}
That might make things a little easier in the long run. It kinda helps you manage state because the quiz type is only one of the three. Although, if the Bools work for you then fair enough.

Swift: Missing Argument Error

Im having an issue here when trying to follow the first stanford lecture. I am assuming it is because I am using swift 2.... which was just recently released. (And the class is not) Below I show where I am getting errors. In the class the "enter" button on the calculator has the code #IBAction func enter() { but in mine it is #IBAction func enter(sender: UIButton) {
Is this something I did wrong when bringing the button into my code? Any ways to fix? Let me know if I can clarify anything.
import UIKit
class ViewController: UIViewController
{
#IBOutlet var display: UILabel!
var userIsInTheMiddleOfTypingANumber: Bool = false
#IBAction func appendDigit(sender: UIButton) {
let digit = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber {
display.text = display.text! + digit
} else {
display.text = digit
userIsInTheMiddleOfTypingANumber = true
}
}
#IBAction func operate(sender: UIButton) {
let operation = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber {
enter() // Here is my error: *Missing Argument for parameter on the line of code that says enter()
}
switch operation {
case "x":
if operandStack.count >= 2 {
displayValue = operandStack.removeLast() * operandStack.removeLast()
enter() // Here is my error: Again...
}
default: break
}
}
var operandStack = Array<Double>()
#IBAction func enter(sender: UIButton) {
userIsInTheMiddleOfTypingANumber = false
operandStack.append(displayValue)
print("operandStack = \(operandStack)")
}
var displayValue: Double {
get {
return NSNumberFormatter().numberFromString(display.text!)!.doubleValue
}
set {
display.text = "\(newValue)"
userIsInTheMiddleOfTypingANumber = false
}
}
}
enter requires an input parameter but you didn't supply it with any. Replace it with enter(sender)
#IBAction func operate(sender: UIButton) {
let operation = sender.currentTitle!
if userIsInTheMiddleOfTypingANumber {
enter(sender)
}
switch operation {
case "x":
if operandStack.count >= 2 {
displayValue = operandStack.removeLast() * operandStack.removeLast()
enter(sender)
}
default: break
}
}