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()
}
}
Related
Here is the error that I am seeing.
The "cardButton" is responsible for showing the next question. This is a small card app game that I am trying to make and as you can see from the image this is where I am having the issue with the code.
Here is the code:
import UIKit
class MultipleViewController: UIViewController {
#IBOutlet weak var questionLabel2: UILabel!
#IBOutlet var answerButtons: [UIButton]!
#IBOutlet weak var cardButton: UIButton!
#IBAction func cardButtonHandle(_ sender: Any) {
cardButton.isEnabled = true
if questionIdx < count(mcArray) - 1 { // There are still more questions
questionIdx += 1 //
} else {
questionIdx = 0
}
nextQuestion()
}
#IBAction func answerButtonHandle(_ sender: UIButton) {
if sender.titleLabel?.text == correctAnswer{
sender.backgroundColor = UIColor.green
print("Correct!")
} else {
sender.backgroundColor = UIColor.red
print("Wrong Answer")
}
for button in answerButtons{
button.isEnabled = false
if button.titleLabel?.text == correctAnswer {
button.backgroundColor = UIColor.green
}
}
cardButton.isEnabled = true // next question
}
var correctAnswer: String? // correct answers
var answers = [String]() // answers
var question : String? // Questions
var questionIdx = 0 // not sure what this is ?
override func viewDidLoad() {
super.viewDidLoad()
// titleForButtons() // call buttons as soon its loaded..
cardButton.isEnabled = false
nextQuestion()
}
func nextQuestion (){
let currentQuestion = mcArray![questionIdx]
answers = currentQuestion["Answers"] as! [String]
correctAnswer = currentQuestion["CorrectAnswer"] as? String
question = currentQuestion["Question"] as? String
titleForButtons ()
}
func titleForButtons (){
for (idx,button) in answerButtons .enumerated() {
button.titleLabel?.lineBreakMode = .byWordWrapping
button.setTitle(answers[idx],for:.normal)
button.isEnabled = true
}
questionLabel2.text = question
}
}
The following should work, you did not have the correct syntax for the length of the array. Note that if you have not initialized your questions array, this would cause a crash. Therefore you might want to add a guard into your code. Perhaps use the following
#IBAction func cardButtonHandle(_ sender: Any) {
cardButton.isEnabled = true
if questionIdx < (mcArray!.count) - 1 { // There are still more questions
questionIdx += 1 //
} else {
questionIdx = 0
}
nextQuestion()
}
How i can call button1() func from calc() with original sender(like if i tap this button)? Call func with nil is bad soulution, because original sender is lost and i cant change button image through sender?.image = UIImage(named: "").
All answers in others topics offer use button.sendActions(for: .touchUpInside). But this solution isn't working.
var var1 = true
var var2 = 1
#IBAction func button1(_ sender: UIBarButtonItem?) {
if var2 == 1 {
sender?.image = UIImage(named: "1")
} else {
sender?.image = UIImage(named: "2")
}
}
func calc() {
if var1 {
button1(nil)
}
}
Make outlet of button and pass the reference as sender
#IBOutlet var outletButton: UIButton!
func calc() {
if var1 {
button1(outletButton)
}
}
var var1 = true
var var2 = 1
#IBAction func button1(_ sender: UIBarButtonItem?) {
button1Action()
}
func button1Action() {
if var2 == 1 {
sender?.image = UIImage(named: "1")
} else {
sender?.image = UIImage(named: "2")
}
}
func calc() {
if var1 {
button1Action()
}
}
you can callself.perform(Selector, with: self)
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.
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
}
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
}
}