Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

My first app.. Help please!

Hi everyone...

I'm trying to create a super simple app, that flips a coin and advises the result, along with updating a counter as to how many times either heads or tails is populated

The app works perfectly.... Except for the counters!! Each time I click the 'Flip a coin" button, the main label updates, and one counter will update (whichever matches the result) but then each time I press the button after that, the counters do not update.

Is anyone able to take a quick look at my code for me and see if they are able to advise why my counters are not updating?

Thank you.

Simon

View Controller

<p>
import UIKit
import GameKit

class ViewController: UIViewController {

    @IBOutlet weak var resultOfFlipText: UILabel!

    @IBOutlet weak var headCount: UILabel!

    @IBOutlet weak var tailsCount: UILabel!

    @IBAction func flipACoinButton() {
        let result = flipCoin()
        flipCounter(result)
        resultOfFlipText.text = result
        headCount.text = displayInstance.headsCountDisplay
        tailsCount.text = displayInstance.tailsCountDisplay
        }



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


}
</p>

And the model

<p>
// Import of code
import UIKit
import GameKit

//Instances, constants & variables

var counterInstance = Counters()
var displayInstance = Displays()

// Display (Converts Int results in Counters to a String

struct Displays {

    var headsCountDisplay = "\(counterInstance.headsCounter)"
    var tailsCountDisplay = "\(counterInstance.tailsCounter)"
}

// Counters (Holds results of flipCounter function)

struct Counters {

    var headsCounter = 0
    var tailsCounter = 0

}

//Coin flip generator

func flipCoin() -> String {
    var resultOfFlip: String
    let randomNumber = GKRandomSource.sharedRandom().nextIntWithUpperBound(2)

    switch randomNumber {
    case 0 : resultOfFlip = "Heads!"
    case 1: resultOfFlip = "Tails!"
    default: resultOfFlip = "Oops, something's gone wrong!"
    }
    return resultOfFlip

}


//Counter (function to calculate result in struct Counters)

func flipCounter (result: String) {
    switch result {
    case "Heads!": counterInstance.headsCounter += 1
    case "Tails!": counterInstance.tailsCounter += 1
    default: print("Something went wrong")
    }
}
</p>

2 Answers

Hey there! So the way this is written the counterInstance is updated on every flip of a coin. However, you are not using the values of counterInstance to update the text fields, but displayInstance. However, you never update the values of displayInstance when the coin is flipped. You have to assign the latest value to displayInstance as well.

The following would work, for example.

func flipCounter (result: String) {
    switch result {
    case "Heads!":
        counterInstance.headsCounter += 1
        displayInstance.headsCountDisplay = "\(counterInstance.headsCounter)"
    case "Tails!":
        counterInstance.tailsCounter += 1
        displayInstance.tailsCountDisplay = "\(counterInstance.tailsCounter)"
    default: print("Something went wrong")
    }
}

Hope that helps :)

That worked!

Thanks so much mate, really appreciate it ?

Hey there! Glad it helped :) I worked through the idea of your code a bit. Please find an example of a bit more Swifty version of your app. I did my best to annotate it, but don't worry if you don't understand everything by now. You can copy and paste this example to a Playground:

//: Playground - noun: a place where people can play

import UIKit
import XCPlayground
import GameKit

// Create fake labels
let headsCountLabel = UILabel()
let tailsCountLabel = UILabel()
let currentSideLabel = UILabel()

// MARK: - Sides enum

// Lets start with an enum call Sides
// For now, let's assume objects only have two sides:
// Top and Bottom.
enum Side {
    case Top
    case Bottom
}

// MARK: Flippable protocol

// Let's describe objects that can be flipped to either
// of the Side enum sides via the Flippable protocol
protocol Flippable {

    // Flippable objects always have a upper side
    var upperSide: Side { get set}

    // We also want to be able to get the name of the
    // upper side of a Flippable
    var upperSideName: String { get }
}

// Moreover, let's extend the flippable protocol
// with a standard behaviour when the object is flipped:
// it assigns uppersSide a random side
extension Flippable {

    // Flip the coin, that is assign a random side
    // to upperSide
    mutating func flip(){
        let randomNumber = GKRandomSource.sharedRandom().nextIntWithUpperBound(2)
        switch randomNumber {
        case 0: upperSide = .Top
        case 1: upperSide = .Bottom
        default: upperSide = .Top
        }
    }
}

// MARK: - The Coin

// Our Coin struct conforms to the Flippable protocol
// and as such can be flipped by calling flip()
// Moreover, it has to have a current upperSide
// and upperSideName value to conform to Flippable.
// Let's say the initial side is always Top
struct Coin: Flippable {

    var upperSide: Side = .Top

    var upperSideName: String {
        return upperSide == .Top ? "Heads" : "Tails"
    }
}

// MARK: - The Counters

struct Counters {

    var heads = 0
    var tails = 0

    // A convenience method to increment the counter
    // according to the result we pass in
    mutating func incremenet(forResult result: Side) {
        switch result {
        case .Top: heads += 1
        case .Bottom: tails += 1
        }
    }
}

// MARK: - Our app logic

// Create a counter
var counters = Counters()

// Create a coin...
var coin = Coin()

// ...and flip it 20 times
for _ in 1...20 {

    coin.flip()

    // Update the counter with the upper side
    counters.incremenet(forResult: coin.upperSide)

    // Update your views accordingly
    currentSideLabel.text = coin.upperSideName
    headsCountLabel.text = "\(counters.heads)"
    tailsCountLabel.text = "\(counters.tails)"

    // For the sake of this playground, let's also print to console
    // Note: never use ! in production
    print("Result: \(currentSideLabel.text!) - Heads: \(headsCountLabel.text!) - Tails: \(tailsCountLabel.text!)")
}

Hey Martin, thanks so much for doing that for me. While I don't understand protocols, enums, or protocols yet, I do have a better understanding of how to structure code now.

I'm going to take the course on enums shortly, afterwards I'll take another look at what you've wrote and hopefully understand it a bit more

Thanks again for your help ?