Try to build a vending mechine IOS app, but there are some error when debug it.
ID: 3840561 • Letter: T
Question
Try to build a vending mechine IOS app, but there are some error when debug it. Someone can help to fix it?
ViewController.Swift code
import UIKit
fileprivate let reuseIdentifier = "vendingItem"
fileprivate let screenWidth = UIScreen.main.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!
@IBOutlet weak var priceLabel: UILabel!
@IBOutlet weak var quantityStepper: UIStepper!
let vendingMachine: VendingMachine
var currentSelection: VendingSelection?
required init?(coder aDecoder: NSCoder) {
do{
let dictionary = try PlistConverter.dictionary(fromFile: "VendInventory", ofType: "Plist")
let inventory = try InventoryUnarchiver.vendingInventory(fromDictionary: 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()
updateDisplayWith(balance: vendingMachine.amountDeposited, totalPrice: 0, itemPrice: 0, itemQuantity: 1)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Setup
func setupCollectionViewCells() {
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 20, right: 0)
let padding: CGFloat = 10
let itemWidth = screenWidth/3 - padding
let itemHeight = screenWidth/3 - padding
layout.itemSize = CGSize(width: itemWidth, height: itemHeight)
layout.minimumLineSpacing = 10
layout.minimumInteritemSpacing = 10
collectionView.collectionViewLayout = layout
}
// mark vendingmachine
@IBAction func Purchase(_ sender: Any) {
if let currentSelection = currentSelection{
do {
try vendingMachine.vend(selection: currentSelection, quantity: Int, quantityStepper.value)
updateDisplayWith(balance: vendingMachine.amountDeposited, totalPrice: 0.0, itemPrice: 0,itemQuantity: 1)
}catch{
//fix: error handing code
}
if let indexPath = collectionView.indexPathsForSelectedItems?.first{
collectionView.deselectItem(at: <#T##IndexPath#>, animated: true)
updateCell(having: <#T##IndexPath#>, selected: false)
}
} else {
// Fix: alert user to no selection
}
}
func updateDisplayWith(balance: Double? = nil, totalPrice: Double? = nil, itemPrice:Double? = nil , itemQuantity: Int? = nil ){
if let balanceValue = balance{
balanceLabel.text = "$(balanceValue)"
}
if let totalValue = balance{
totalLabel.text = "$(totalValue)"
}
if let priceValue = itemPrice{
priceLabel.text = "$(priceValue)"
}
if let quantityValue = itemQuantity{
quantityLabel.text = "(quantityValue)"
}
}
func updateTotalPrice(for item: VendingItem){
let totalPrice = item.price * quantityStepper.value
updateDisplayWith(totalPrice: totalPrice)
}
@IBAction func updateQuantity(_ sender: UIStepper) {
let quantity = Int(quantityStepper.value)
updateDisplayWith(itemQuantity: quantity)
if let cuerrentSelection = currentSelection, let item = vendingMachine.item(forSelection: currentSelection!){
updateTotalPrice(for: item)
}
}
// MARK: UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return vendingMachine.selection.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as? VendingItemCell else { fatalError() }
let item = vendingMachine.selection[indexPath.row]
cell.iconView.image = item.icon()
return cell
}
// MARK: - UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
updateCell(having: indexPath, selected: true)
quantityStepper.value = 1
updateDisplayWith(totalPrice: 0, itemQuantity: 1)
currentSelection = vendingMachine.selection[indexPath.row]
if let currentSelection = currentSelection, let item = vendingMachine.item(forSelection: currentSelection){
let totalPrice = item.price * quantityStepper.value
updateDisplayWith(totalPrice: totalPrice, itemPrice: item.price)
}
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
updateCell(having: indexPath, selected: false)
}
func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
updateCell(having: indexPath, selected: true)
}
func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) {
updateCell(having: indexPath, selected: false)
}
func updateCell(having indexPath: IndexPath, selected: Bool) {
let selectedBackgroundColor = UIColor(red: 41/255.0, green: 211/255.0, blue: 241/255.0, alpha: 1.0)
let defaultBackgroundColor = UIColor(red: 27/255.0, green: 32/255.0, blue: 36/255.0, alpha: 1.0)
if let cell = collectionView.cellForItem(at: indexPath) {
cell.contentView.backgroundColor = selected ? selectedBackgroundColor : defaultBackgroundColor
}
}
}
VendingMechine.Swift code
import Foundation
import UIKit
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 #imageLiteral(resourceName: "default")
}
}
}
protocol VendingItem {
var price: Double {get}
var quantity: Int {get}
}
protocol VendingMachine{
var selection: [VendingSelection] { get }
var inventory: [VendingSelection: VendingItem] {get set}
var amountDeposited: Double {get set}
init(inventory: [VendingSelection: VendingItem])
func vend(selection: VendingSelection, quantity: Int ) throws
func deposit(_amount: Double)
func item(forSelection selecion: VendingSelection) -> VendingItem?
}
struct Item:VendingItem {
let price: Double
var quantity: Int
}
enum InventoryError: Error {
case invalidResource
case conversionFailure
case invalidSelection
}
class PlistConverter{
static func dictionary(fromFile name: String, ofType type:String)throws -> [String:AnyObject]{
guard let path = Bundle.main.path(forResource: name,ofType:type)else{
throw InventoryError.invalidResource
}
guard let dictionary = NSDictionary(contentFile:path) as? [String:AnyObject] else {
throw InventoryError.conversionFailure
}
return dictionary
}
}
class InventoryUnarchiver{
static func vendingInventory(fromDictionary dictionary: [String:AnyObject]) -> [VendingSelection: VendingItem]{
var inventory:[VendingSelection: VendingItem] = [:]
for (key,value) in dictionary{
if let itemDictionary = value as? [String:Any], let price = itemDictionary["price"] as? Double, let quantity = itemDictionary["quantity"] as? Int {
let item = Item(price:price, quantity:quantity)
guard let selection = VendingSelection(rawValue:key) else{
throw InventoryError.invalidResource
}
inventory.updateValue(item, forKey: selection)
}
return inventory
}
}
enum VendingMachineError: Error {
case invalidSelection
case outOfStock
case insufficientFunds(require: Double)
}
class FoodVendingMachine: VendingMachine{
let selection: [VendingSelection] = [.soda,.dietSoda,.chips,.cookie,.wrap,.sandwich,.candyBar,.popTart,.water,.fruitJuice,.sportsDrink,.gum]
var inventory: [VendingSelection : VendingItem]
var amountDeposited: Double = 10.0
required init(inventory: [VendingSelection : VendingItem]) {
self.inventory = inventory
}
func vend(selection: VendingSelection,quantity: Int) throws {
guard var item = inventory[selection]else{
throw VendingMachineError.invalidSelection
}
guard item.quantity >= quantity else{
throw VendingMachineError.outOfStock
}
let totalPrice = item.price * Double (quantity)
if amountDeposited >= totalPrice{
amountDeposited -= totalPrice
item.quantity -= quantity
inventory.updateValue(item, forKey: selection)
}else{
let amountRequired = totalPrice - amountDeposited
throw VendingMachineError.insufficientFunds(require: amountRequired)
}
}
func deposit(_amount: Double) {
<#code#>
}
func item(forSelection selecion: VendingSelection) -> VendingItem? {
return inventory[selection]
}
}
L Vending Machine v Vending Machine AppDelegate swift ViewController swift VendingitemC Vending Mechine.switt Main storyboard B Assets.cocassets aunchscreen storyboard info.plist Vendinginventory.plist Products dat UIKit Vend gselect oda diet Soda chips cookie andwich wrap dyB popTart tJu portsDrink gum inage mage(named sel rawValue) image return vending Item var price Double (get) var quantity: Int {gat) dingMach var selection [Vendingselection] get inventory Vending Selection Vending Item get Bet Deposited inventory Vendingselection Vending Item func vend( selection: Vendingselection, quantity: Int throws dep unt func item(forselection selecion: Vendingselection Vending Iten Vending Iten Item price: Double var quantity IntExplanation / Answer
According to record, When you import Swift code into Objective-C, you depend on a Xcode-created header document to open those records to Objective-C. This naturally produced record is an Objective-C header that announces the Swift interfaces in your objective. It can be considered as an umbrella header for your Swift code. The name of this header is your item module name taken after by including "- Swift.h".
As a matter of course, the produced header contains interfaces for Swift affirmations set apart with the general population modifier. It additionally contains those set apart with the inside modifier if your application target has an Objective-C connecting header. Statements set apart with the private modifier don't show up in the produced header. Private announcements are not presented to Objective-C unless they are expressly set apart with @IBAction, @IBOutlet, or @objc too. On the off chance that your application target is gathered with testing empowered, a unit test target can get to any affirmation with the inner modifier as though they were announced with people in general modifier by prepending @testable to the item module import articulation.
You don't have to do anything extraordinary to make the created header record—simply import it to utilize its substance in your Objective-C code. Take note of that the Swift interfaces in the created header incorporate references to the majority of the Objective-C sorts utilized as a part of them. In the event that you utilize your own Objective-C sorts in your Swift code, try to import the Objective-C headers for those sorts before bringing in the Swift produced header into the Objective-C .m record you need to get to the Swift code from.
For more subtle elements take after this Importing Swift into Objective-C