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 Build a Vending Machine App in Swift 2.0 Using the Vending Machine Testing Out the Vending Machine

Brian Uribe
Brian Uribe
3,488 Points

Cannot Subscript

For the line of code currentSelection = vendingMachine.selection[indexPath.row] I get an error saying that I cannot subscript a value type of [VendingSelection]. What is going on? Shouldn't it say vendingMachine?

2 Answers

Steven Deutsch
Steven Deutsch
21,046 Points

Hey Brian Uribe,

I'm thinking that you have your currentSelection variable set to the wrong type. You might have it as [VendingSelection] when it needs to be of type VendingSelection.

This is how it should read:

  var currentSelection: VendingSelection?

Let me know if this helps. If not, please show me your view controller code. Your VendingMachine.swift file would also be helpful. Thanks

Brian Uribe
Brian Uribe
3,488 Points

Thank you! I ran into more trouble, i'm starting to think I missed a step somewhere. In the video we move one line of code

{ if let currrentSelection = currentSelection, let item = vendingMachine.itemForCurrentSelection(currentSelection) totalLabel.text = "$(item.price * quantity)" }

from one function to another and I suddenly got a ton of errors. I'm feeling a pit overwhelmed.

here is my vending machine code:

// // VendingMachine.swift // VendingMachine // // Created by Admin on 3/14/16. // Copyright © 2016 Treehouse. All rights reserved. //

import Foundation import UIKit // Protocols

protocol VendingMachineType { var selection: [VendingSelection] { get } var inventory: [VendingSelection: ItemType] { get set } var amountDeposited: Double { get set }

init(inventory: [VendingSelection: ItemType])
func vend(selection: VendingSelection, quantity: Double) throws
func deposit(amount: Double)
func itemForCurrentSelection(selection: VendingSelection) -> ItemType?

}

protocol ItemType { var price: Double { get } var quantity: Double { get set } }

// Error Types

enum InventoryError: ErrorType {

case InvalidResource
case ConversionError
case InvalidKey

}

enum VendingMachineError: ErrorType { case InvalidSelection case OutOfStock case InsufficientFunds(required: Double) }

// Helper Classes

class PlistConverter { class func dictionaryFromFile(resource: String, ofType type: String) throws-> [String : AnyObject] {

    guard let path = NSBundle.mainBundle().pathForResource(resource, ofType: type) else {
        throw InventoryError.InvalidResource
    }

    guard let dictionary = NSDictionary(contentsOfFile: path), let castDictionary = dictionary as? [String: AnyObject] else {
        throw InventoryError.ConversionError
    }

    return castDictionary
}

}

class InventoryUnarchiver { class func vendingInventoryFromDictionary(dictionary: [String : AnyObject]) throws -> [VendingSelection : ItemType] { var inventory: [VendingSelection : ItemType] = [:]

    for (key, value) in dictionary {
        if let itemDict = value as? [String : Double], let price = itemDict["price"], let quantity = itemDict["quantity"] {

            let item = VendingItem(price: price, quantity: quantity)

            guard let key = VendingSelection(rawValue: key) else {
                throw InventoryError.InvalidKey
            }

            inventory.updateValue(item, forKey: key)
        }

    }

    return inventory
}
}

// Concrete Types

enum VendingSelection: String { case Soda case DietSoda case Chips case Cookie case Sandwich case Wrap case CandyBar case PopTart case Water case FruitJuice case SportsDrink case Gum

func icon() -> UIImage {
    if let image = UIImage(named: self.rawValue) {
        return image
    } else {
        return UIImage(named: "Default")!
    }

}

}

struct VendingItem: ItemType{ var price: Double var quantity: Double }

class VendingMachine: VendingMachineType { let selection: [VendingSelection] = [.Soda, .DietSoda, .Chips, .Cookie, .Sandwich, .Wrap, .CandyBar, .PopTart, .Water, .FruitJuice, .SportsDrink, .Gum] var inventory: [VendingSelection: ItemType] var amountDeposited: Double = 10.0

required init(inventory: [VendingSelection : ItemType]) {
self.inventory = inventory

} func vend(selection: VendingSelection, quantity: Double) throws { guard var item = inventory[selection] else { throw VendingMachineError.InvalidSelection }

guard item.quantity > 0 else {
    throw  VendingMachineError.OutOfStock
}

item.quantity -= quantity
inventory.updateValue(item, forKey: selection)

let totalPrice = item.price * quantity
if amountDeposited >= totalPrice {
    amountDeposited -= totalPrice
} else {
    let amountRequired = totalPrice - amountDeposited
    throw VendingMachineError.InsufficientFunds(required: amountRequired)
}

}

func itemForCurrentSelection(selection: VendingSelection) -> ItemType? {
    return inventory[selection]
}

func deposit(amount: Double) { //add code } }

and then here is the view controller code:

// // ViewController.swift // VendingMachine // // Created by Pasan Premaratne on 1/19/16. // Copyright © 2016 Treehouse. All rights reserved. //

import UIKit

private let reuseIdentifier = "vendingItem" private let screenWidth = UIScreen.mainScreen().bounds.width

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

@IBOutlet weak var collectionView: UICollectionView!
@IBOutlet weak var totalLabel: UILabel!
@IBOutlet weak var balanceLabel: UILabel!
@IBOutlet weak var quantityLabel: UILabel!

let vendingMachine: VendingMachineType
var currentSelection: VendingMachine?
var quantity: Double = 1.0


required init?(coder aDecoder: NSCoder) {

    do {
        let dictionary = try PlistConverter.dictionaryFromFile("VendingInventory", ofType: "plist")
        let inventory = try InventoryUnarchiver.vendingInventoryFromDictionary(dictionary)
        self.vendingMachine = VendingMachine(inventory: inventory)
    } catch let error {
        fatalError("\(error)")
    }
    super.init(coder: aDecoder)
}

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    setupCollectionViewCells()
    setupViews()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func setupViews() {
    updateQuantityLabel()
    updateBalanceLabel()
}

// MARK: - UICollectionView 

func setupCollectionViewCells() {
    let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
    layout.sectionInset = UIEdgeInsets(top: 20, left: 0, bottom: 10, right: 0)
    let padding: CGFloat = 10
    layout.itemSize = CGSize(width: (screenWidth / 3) - padding, height: (screenWidth / 3) - padding)
    layout.minimumInteritemSpacing = 10
    layout.minimumLineSpacing = 10

    collectionView.collectionViewLayout = layout
}

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return vendingMachine.selection.count
}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! VendingItemCell


    let item = vendingMachine.selection[indexPath.row]
    cell.iconView.image = item.icon()

    return cell
}

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
    updateCellBackgroundColor(indexPath, selected: true)
    reset()
    currentSelection = vendingMachine.selection[indexPath.row]
    updateTotalPrice()



func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
    updateCellBackgroundColor(indexPath, selected: false)
}

func collectionView(collectionView: UICollectionView, didHighlightItemAtIndexPath indexPath: NSIndexPath) {
    updateCellBackgroundColor(indexPath, selected: true)
}

func collectionView(collectionView: UICollectionView, didUnhighlightItemAtIndexPath indexPath: NSIndexPath) {
    updateCellBackgroundColor(indexPath, selected: false)
}

func updateCellBackgroundColor(indexPath: NSIndexPath, selected: Bool) {
    if let cell = collectionView.cellForItemAtIndexPath(indexPath) {
        cell.contentView.backgroundColor = selected ? UIColor(red: 41/255.0, green: 211/255.0, blue: 241/255.0, alpha: 1.0) : UIColor.clearColor()
    }
}

// MARK: - Helper Methods
@IBAction func purchase() {
    if let currentSelection = currentSelection {
        do {
            try vendingMachine.vend(currentSelection, quantity: quantity)
           updateBalanceLabel()
        } catch {
            //FIXME: Error Handling Code
        }
    } else {
        // FIXME: Alert user to no selection
    }

}



@IBAction func updateQuantity(sender: UIStepper) {
    quantity = sender.value
    updateTotalPriceLabel()
    updateQuantityLabel()
}

    func updateTotalPrice () { if let currrentSelection = currentSelection, let item = vendingMachine.itemForCurrentSelection(currentSelection)
    totalLabel.text = "$\(item.price * quantity)"
}
}

func updateQuantityLabel() {
    quantityLabel.text = "\(quantity)"
}

func updateBalanceLabel() {
    balanceLabel.text = "$\(vendingMachine.amountDeposited)"

}

func reset() {
    quantity = 1
    updateTotalPriceLabel()
    updateQuantityLabel()
}

}

Brian Uribe
Brian Uribe
3,488 Points

That posted in an unreadable fashion. How can I show you the code in a more readable format?

Steven Deutsch
Steven Deutsch
21,046 Points

Yeah that is a bit of a mess for me to work with? Did your first error get solved by what I suggested, or does it still exist? As for moving some code and receiving errors, I would recommend rewatching the video and matching your code with Pasan's.