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
philip williams
5,991 PointsThe VendingMachine app keeps crashing after completing the finishing touches video any help?
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) }
The app crashes at this point at the end of the video "Finishing Touches" , now I can't test the app. any help would be greatly appreciated.
6 Answers
philip williams
5,991 PointsHi Steven, I don't know where to find the info you need, sorry
philip williams
5,991 PointsIt took me a while but I finally found the button i needed to press. Here is the debugger output message;
fatal error: InvalidKey: file /Users/philwilliams/Downloads/VendingMachineStarterFiles/VendingMachine/ViewController.swift, line 29 (lldb)
Steven Deutsch
21,046 PointsSorry I missed this. This means your code is crashing because of the error handling you set up. You're returning an invalid key and the fatal error method is being called. Can you post your VendingMachine.swift file for me?
philip williams
5,991 Points// // VendingMachine.swift // VendingMachine // // Created by Phil Williams on 18/03/2016. // Copyright © 2016 Treehouse. All rights reserved. //
import Foundation
// 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)
}
protocol ItemType { var price: Double { get } var quantity: Double { get set } }
// Error Types
enum InventoryError: ErrorType { case InvalidResource case ConversionError case InvalidKey }
// 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 }
struct VendingItem: ItemType { let 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 {
// add code
}
func deposit(amount: Double) {
// add code
}
}
I really hope this is the info you are asking for.
Steven Deutsch
21,046 PointsHow about the view controller too? I can't find the problem. I'm missing something. You have the VendingInventory.plist file, right?
philip williams
5,991 Points// // 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
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()
print(vendingMachine.inventory)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// 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
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
updateCellBackgroundColor(indexPath, selected: true)
}
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
}
philip williams
5,991 PointsI have the VendingInventory.plist but i can't figure out how to post it here.
Steven Deutsch
21,046 PointsHey Philip, No worries. I don't need the plist file. I just wanted to make sure it was in your bundle. I still can't find the problem :( I would backtrack and rewatch his videos, comparing your code line for line.
Steven Deutsch
21,046 PointsSteven Deutsch
21,046 PointsHey philip williams,
Could you post the debugger output with the error message please? Thanks!