maximum/minimum on incrementing buttons - swift

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
}

Related

How Can I Make A Timer Using String In xCode

So I'm trying to make a chess timer. I'm using string to make the 00:00 in a variable called storeTimed. Is there a way possible to make that used an timer to count down from that?
Here's my code:
The part I need help with is the updateTimer() function. Since the storedTime is a string trying to pass as a Int, xCode isn't liking it. I'm honestly not very sure what I could do. Mostly at the else statement, but the whole part in general
class ChessTimer: UIViewController {
#IBOutlet weak var playerTimer1: UILabel!
#IBOutlet weak var playerTimer2: UILabel!
var timer = Timer()
var time = 10
var isTimerRunning = false
var storedTime = "00:00"
override func viewDidLoad() {
super.viewDidLoad()
if isTimerRunning == false {
runTimer()
}
}
#IBAction func restartButton(_ sender: UIButton) {
}
#IBAction func pausePressed(_ sender: UIButton) {
timer.invalidate()
}
#IBAction func settingsPressed(_ sender: UIButton) {
performSegue(withIdentifier: "goToSettings", sender: self)
}
func runTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self,selector: (#selector(ChessTimer.updateTimer)),userInfo: nil, repeats: true)
isTimerRunning = true
}
#objc func updateTimer() {
if Int(storedTime) < 1 {
timer.invalidate()
playerTimer1.text = "00:00"
playerTimer2.text = "00:00"
}
else {
Int(storedTime)! -= 1
playerTimer1.text = prodTimeString(time: TimeInterval(storedTime)!)
}
}
func prodTimeString(time: TimeInterval) -> String {
let prodMinutes = Int(time) / 60 % 60
let prodSeconds = Int(time) % 60
return String(format: "%02d:%02d", prodMinutes, prodSeconds)
}
#IBAction func playerButton1(_ sender: UIButton) {
}
#IBAction func playerButton2(_ sender: UIButton) {
}
#IBAction func unwindToVC1(sender: UIStoryboardSegue) {
if let settingsController = sender.source as? SettingsController {
playerTimer1.text = settingsController.storedTime
playerTimer2.text = settingsController.storedTime
storedTime = settingsController.storedTime
}
}
}
To keep things simple, here's the code. I have removed the functions that aren't relevant to the discussion - non-implemented buttons, etc.,
The simple idea is that you use numbers (Int / Double / whatever) to store variables that you are counting with, and then have helper functions to present the variable in different formats
import UIKit
class ChessTimer: UIViewController {
var timer = Timer()
var isTimerRunning = false
var storedTime : Int = 0 // use an integer to store the time
override func viewDidLoad() {
super.viewDidLoad()
if isTimerRunning == false {
runTimer()
}
}
func runTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self,selector: (#selector(ChessTimer.updateTimer)),userInfo: nil, repeats: true)
isTimerRunning = true
}
#objc func updateTimer() {
// because we're storing the value in an Int, we don't need to convert it here
storedTime -= 1
if storedTime < 1 {
timer.invalidate()
// use the helper function to format the result for zero time as well as everything else
// that way, if you ever change it, you only have to change in one place
playerTimer1.text = prodTimeString(0)
playerTimer2.text = prodTimeString(0)
}
else {
playerTimer1.text = prodTimeString(storedTime)
}
}
func prodTimeString(_ time: Int) -> String {
// because there's only one parameter, and it's obvious, add '_' then you don't need the label when you call it
let prodMinutes = time / 60 % 60
let prodSeconds = time % 60
return String(format: "%02d:%02d", prodMinutes, prodSeconds)
}
}

go back and forth a string-array with two buttons

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
}

How can I get the game to show the word after all guesses have been used up?

so I'm new to coding and I've been doing practice games a such to build my skills. I've created this word guessing game and I'm trying to make the game show the word after all guesses have been used up. However, the program doesn't read the code I write to set the label to display the answer. Here is the code I've written so far:
class ViewController: UIViewController {
var listOfWords = ["ladybug", "program", "computer", "language", "glorious", "incandescent"]
let incorrectMovesAllowed = 7
var totalWins = 0 {
didSet {
newRound()
}
}
var totalLosses = 0 {
didSet {
newRound()
}
}
#IBOutlet var letterButtons: [UIButton]!
#IBAction func buttonPressed(_ sender: UIButton) {
sender.isEnabled = false
let letterString = sender.title(for: .normal)!
let letter = Character(letterString.lowercased())
currentGame.playerGuessed(letter: letter)
updateUI()
updateGameState()
}
#IBOutlet weak var scoreLabel: UILabel!
#IBOutlet weak var correctWordLabel: UILabel!
#IBOutlet weak var treeImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
newRound()
// Do any additional setup after loading the view, typically from a nib.
}
func enableLetterButtons (_enable: Bool){
for button in letterButtons {
button.isEnabled = _enable
}
}
var currentGame : Game!
func newRound() {
if !listOfWords.isEmpty{
let newWord = listOfWords.removeFirst()
currentGame = Game (word: newWord, incorrectMovesRemaining: incorrectMovesAllowed, guessedLetters: [])
enableLetterButtons(_enable: true)
updateUI()
} else {
enableLetterButtons (_enable: false)
}
}
func updateUI() {
var letters = [String] ()
for letter in currentGame.formattedWord.characters {
letters.append(String(letter))
}
let wordWithSpacing = letters.joined(separator: " ")
correctWordLabel.text = wordWithSpacing
scoreLabel.text = "Wins: \(totalWins), Losses:\(totalLosses)"
treeImageView.image = UIImage (named: "Tree \(currentGame.incorrectMovesRemaining)")
}
func updateGameState(){
var letters = [String] ()
for letter in currentGame.word.characters {
letters.append(String(letter))
}
let theAnswer = letters.joined(separator: " ")
if currentGame.incorrectMovesRemaining == 0 {
correctWordLabel.text = theAnswer
Thread.sleep(forTimeInterval: 3)
totalLosses += 1
} else if currentGame.word == currentGame.formattedWord {
totalWins += 1
} else {
updateUI()
}
}
}
In addition, I have a structure that is written like this:
import Foundation
struct Game {
var word : String
var incorrectMovesRemaining : Int
var guessedLetters: [Character]
mutating func playerGuessed (letter: Character){
guessedLetters.append(letter)
if !word.characters.contains(letter){
incorrectMovesRemaining -= 1
}
}
var formattedWord: String {
var guessedWord = ""
for letter in word.characters {
if guessedLetters.contains(letter) {
guessedWord += "\(letter)"
} else {
guessedWord += "_"
}
}
return guessedWord
}
}
You need to redraw your UI, this is done with self.setNeedsDisplay(). It notifies the system that the view's contents needs to be redrawn. In your updateUI() you can add this.
Regarding setNeedsDisplay you can get more information here
class ViewController: UIViewController {
var listOfWords = ["ladybug", "program", "computer", "language", "glorious", "incandescent"]
let incorrectMovesAllowed = 7
var totalWins = 0 {
didSet {
newRound()
}
}
var totalLosses = 0 {
didSet {
newRound()
}
}
#IBOutlet var letterButtons: [UIButton]!
#IBAction func buttonPressed(_ sender: UIButton) {
sender.isEnabled = false
let letterString = sender.title(for: .normal)!
let letter = Character(letterString.lowercased())
currentGame.playerGuessed(letter: letter)
updateUI()
updateGameState()
}
#IBOutlet weak var scoreLabel: UILabel!
#IBOutlet weak var correctWordLabel: UILabel!
#IBOutlet weak var treeImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
newRound()
// Do any additional setup after loading the view, typically from a nib.
}
func enableLetterButtons (_enable: Bool){
for button in letterButtons {
button.isEnabled = _enable
}
}
var currentGame : Game!
func newRound() {
if !listOfWords.isEmpty{
let newWord = listOfWords.removeFirst()
currentGame = Game (word: newWord, incorrectMovesRemaining: incorrectMovesAllowed, guessedLetters: [])
enableLetterButtons(_enable: true)
updateUI()
} else {
enableLetterButtons (_enable: false)
}
}
func updateUI() {
var letters = [String] ()
for letter in currentGame.formattedWord.characters {
letters.append(String(letter))
}
let wordWithSpacing = letters.joined(separator: " ")
correctWordLabel.text = wordWithSpacing
scoreLabel.text = "Wins: \(totalWins), Losses:\(totalLosses)"
treeImageView.image = UIImage (named: "Tree \(currentGame.incorrectMovesRemaining)")
self.setNeedsDisplay()
}
func updateGameState(){
var letters = [String] ()
for letter in currentGame.word.characters {
letters.append(String(letter))
}
let theAnswer = letters.joined(separator: " ")
if currentGame.incorrectMovesRemaining == 0 {
correctWordLabel.text = theAnswer
Thread.sleep(forTimeInterval: 3)
totalLosses += 1
} else if currentGame.word == currentGame.formattedWord {
totalWins += 1
} else {
updateUI()
}
}
}
Create a variable that will keep track of how many times you have guessed wrong. Then you can do this:
Use a while statement:
while numberOfTimesGuessedWrong <= 7{
}
//when you have guessed incorrectly 7 times, the compiler will move here:
wordLabel.text = "\(correctAnswer)"
So when you guess incorrectly 7 times, on the 8th time, it will then show the correct answer.

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
}
}

Swift Calculator from Stanford Swift Course

We worked on calculator from Stanford swift course and we got stuck on calling methods performOperation where errors occur (use of local variable " performOperation " before its declaration).Any help or suggestions to solve the problem will be appreciated.Thanks
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var display: UILabel!
var userIsInTheMiddleOfTypingNumber: Bool = false
#IBAction func appendDigit(sender: UIButton){
let digit = sender.currentTitle!
if userIsInTheMiddleOfTypingNumber {
display.text = display.text! + digit
}
else {
display.text = digit
userIsInTheMiddleOfTypingNumber = true
}
//println("digit = \(digit)")
}
#IBAction func operate(sender: UIButton) {
let operation = sender.currentTitle!
if userIsInTheMiddleOfTypingNumber {
enter()
}
switch operation {
case"×": performOperation() { $0 * $1 } - THIS IS THE CODE WHERE WE GOT ERROR
// case"÷":
// case"+":
// case"-":
default: break
}
func performOperation(operation: (Double, Double) -> Double) {
if operandStack.count >= 2 {
displayValue = operation(operandStack.removeLast(), operandStack.removeLast())
enter()
}
}
}
var operandStack = Array<Double>()
#IBAction func enter() {
userIsInTheMiddleOfTypingNumber = false
operandStack.append(displayValue)
println("operandStack = \(operandStack)")
}
var displayValue: Double {
get {
return NSNumberFormatter().numberFromString(display.text!)!.doubleValue
}
set{
display.text = "\(newValue)"
userIsInTheMiddleOfTypingNumber = false
}
}
}
I think your performOperation function should be outside the your #IBAction function as given below:
#IBAction func operate(sender: UIButton) {
let operation = sender.currentTitle!
if userIsInTheMiddleOfTypingNumber {
enter()
}
switch operation {
case"×": performOperation() { $0 * $1 } - THIS IS THE CODE WHERE WE GOT ERROR
// case"÷":
// case"+":
// case"-":
default: break
}
}
func performOperation(operation: (Double, Double) -> Double)
{
if operandStack.count >= 2 {
displayValue = operation(operandStack.removeLast(), operandStack.removeLast())
enter()
}
}