Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

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 Int

Explanation / 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