Fatal Error creating Array - ios

This is the code I have. Basically when the user first chooses the quality of the dinning whether it is fine (20%), casual (15%), or a bar (11%). From there the user will then be asked on a 1-5 scale about the food quality, service, etc. Depending what number they choose, for example if the fine dinning was a 5/5 then it will ad 4% to the already 20 percent (each number will have a selected value to add to the tip). Can anyone figure out what's going on? Or if there is a better way about doing it.
import UIKit
#IBDesignable
class ViewController: UIViewController {
#IBOutlet weak var billTotal: UITextField!
var diningValue: Double = 0.0
#IBAction func toggleFineDining(sender: UIButton) {
sender.highlighted = sender.selected
if sender.selected == true{
diningValue = 0.20
}
}
#IBAction func toggleCasualDining(sender: UIButton) {
sender.highlighted = sender.selected
if sender.selected == true{
diningValue = 0.15
}
}
#IBAction func toggleBartender(sender: UIButton) {
sender.highlighted = sender.selected
if sender.selected == true{
diningValue = 0.11
}
}
#IBOutlet weak var service: UITextField!
#IBOutlet weak var friendliness: UITextField!
#IBOutlet weak var foodQuality: UITextField!
#IBOutlet weak var atmosphere: UITextField!
#IBOutlet weak var overall: UITextField!
#IBOutlet weak var recommend: UISwitch!
#IBOutlet weak var total: UILabel!
func totalBill(inputArray: [Double], value: Double, recommend: Bool)->Double{
var array: [Double] = []
let total = inputArray[0]
for var i = 1; i < inputArray.count; ++i {
array.append(inputArray[i] * 0.01)
}
let sum = array.reduce(0, combine: +)
var totalTip = Double()
if recommend == true{
totalTip = sum + value
} else {
if sum < 0.15 {
totalTip = 0.15
} else {
totalTip = sum + value
}
}
let tipValue = totalTip * total
return total + tipValue
}
#IBAction func calcTotal(sender: AnyObject) {
var valueList = [String(service.text), String(friendliness.text), String(foodQuality.text), String(atmosphere.text), String(overall.text)]
let list = doubleArray(valueList)
print(list)
let initialTotal = Double(billTotal.text!)
let total_bill = totalBill(list, value: diningValue, recommend: recommend.selected)
print("Total: ", total_bill)
print(String(format: "%.3f", Double(total_bill)))
total.text = "$" + String(format: "%.2f", Double(total_bill))
//diningValue = diningValue
}
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.
}
}
func doubleArray(list: [String])->[Double]{
var doubledList: [Double] = []
for element in 0...list.count{
let doubledElement = Double(list[element])
doubledList.append(doubledElement!)
}
return doubledList
}

Your issue is in the last function:
func doubleArray(list: [String])->[Double]{
var doubledList: [Double] = []
for element in 0...list.count{
let doubledElement = Double(list[element])
doubledList.append(doubledElement!)
}
return doubledList
}
Your loop is looping from 0 to list.count and it crashes at list[element] when element is list.count (Out of Index)
You need to change from 0...list.count to 0..<list.count:
func doubleArray(list: [String])->[Double]{
var doubledList: [Double] = []
for element in 0..<list.count{
let doubledElement = Double(list[element])
doubledList.append(doubledElement!)
}
return doubledList
}
I would recommend you to do it in swifty way:
func doubleArray(list: [String])->[Double]{
var doubledList: [Double] = []
for element in list {
doubledList.append(Double(element) ?? 0.0)
}
return doubledList
}
A shorter version using map function:
func doubleArray(list: [String])->[Double]{
return list.map( { Double($0) ?? 0.0 })
}

Related

How to check if a user inputed answer has letters, and if so, how would you just default that answer into a 0?

Heres the code I have so far, now when a user inputs any letter, my label display nothing, what I would like to figure out is how to turn that nothing "", into a 0. I tried doing an if statement on my "label.txt ="'s but that didn't pan out. What would be a better way of finding my desired results?
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var game1: UITextField!
#IBOutlet weak var game2: UITextField!
#IBOutlet weak var game3: UITextField!
#IBOutlet weak var series: UILabel!
#IBOutlet weak var average: UILabel!
#IBOutlet weak var high: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func calculate(_ sender: Any) {
self.view.endEditing(true)
guard
let text1 = game1.text,
let text2 = game2.text,
let text3 = game3.text
else { return }
guard
let game1Results = Int(text1),
let game2Results = Int(text2),
let game3Results = Int(text3)
else { return }
let gameResultsArray = [game1Results, game2Results, game3Results]
let sumArray = gameResultsArray.reduce(0, +)
let positiveArray = gameResultsArray.filter {
(item: Int) -> Bool in return item > 0
}
var avgArrayValue = 0
if positiveArray.count == 0
{
avgArrayValue = 0
}else {
avgArrayValue = sumArray / positiveArray.count
}
series.text = "\(sumArray)"
average.text = "\(avgArrayValue)"
if let maximumVal = gameResultsArray.max() {
high.text = String(maximumVal)
}
}
}
Here is what you need, convert String to Int and give the default 0. Instead of using the guard let return use this method:
Instead of this:
guard let game1Results = Int(text1) else { return }
Use this:
let game1Results = Int(text1) ?? 0

How to find the average of just the user inputs above 0

so I'm trying to find the average of my results using only user inputed values above 0. I'm not sure how I would check the results in the array to find out which values are above 0 and exclude them from the calculation in swift.
class ViewController: UIViewController {
#IBOutlet weak var game1: UITextField!
#IBOutlet weak var game2: UITextField!
#IBOutlet weak var game3: UITextField!
#IBOutlet weak var series: UILabel!
#IBOutlet weak var average: UILabel!
#IBOutlet weak var high: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func calculate(_ sender: Any) {
self.view.endEditing(true)
guard
let text1 = game1.text,
let text2 = game2.text,
let text3 = game3.text
else { return }
guard
let game1Results = Int(text1),
let game2Results = Int(text2),
let game3Results = Int(text3)
else { return }
let gameResultsArray = [game1Results, game2Results, game3Results]
let sumArray = gameResultsArray.reduce(0, +)
let avgArrayValue = sumArray / gameResultsArray.count
series.text = "\(sumArray)"
average.text = "\(avgArrayValue)"
if let maximumVal = gameResultsArray.max() {
high.text = String(maximumVal)
}
}
}
To filter out all values above 0 in an array, use the filter method. This will return a subset of your original array with all values passing the condition declared inside -
var demoArray = [-1, -8, 0, 1, 5 ,6]
var positiveArray = demoArray.filter { (item: Int) -> Bool in
return item > 0
}
print(positiveArray) // [1, 5, 6]
simply you can use filter
..
let sumArray = gameResultsArray.filter({$0 > 0})
let avgArrayValue = sumArray.reduce(0, +) / sumArray.count

Fatal error when unwrapping a segued string (swift3)

This is my code I don't know what I did wrong. All of the problems are in function steve. LebelText is a timer timer label that is segued from another view controller. So i want to take lebetText convert it to a int to subtract 1 from it then reconvert it back to a string to display the number.
This is view Controller a. The texted being segued is lebelText.
import UIKit
class testViewController: UIViewController {
#IBOutlet var lazel: UILabel!
#IBOutlet var plax: UIButton!
#IBOutlet var stopx: UIButton!
var timer = Timer()
var counter = 0.0
var isRunning = false
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let DestViewController : restultViewController = segue.destination as! restultViewController
DestViewController.LebelText = lazel.text!
}
#IBAction func play(_ sender: Any) {
if !isRunning{
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(testViewController.update), userInfo: nil, repeats: true)
}
plax.isEnabled = false
stopx.isEnabled = true
}
#IBAction func stop(_ sender: Any) {
plax.isEnabled = true
stopx.isEnabled = false
timer.invalidate()
isRunning = false
}
func update(){
counter += 0.1
lazel.text = String(format: "1%f", counter)
lazel.text = "\(counter)"
}}
this is view controller b. The goal is to go to take lebelText convert it to a int to subtracted 1 from it. Then convert it back to a string so it can be displayed.
import UIKit
class restultViewController: UIViewController {
#IBOutlet var dxe: UILabel!
var LebelText = String()
let myInt = Int()
override func viewDidLoad() {
super.viewDidLoad()
steve()
}
func steve(){
var eq = LebelText
var intValue = Int(eq)
let vx = intValue! - 1
let ramit = String(vx)
dxe.text = ramit
}
ok so to get rid of the optional and to be sure it all works you should do like
if let intValue = Int(eq) {
vx = intValue - 1
dxe.text = String(vx)
} else {
//do some stuff if you cannot convert eq to Int
}
but I would recommend you to start with some easier tasks, it looks like you did not completely learn basics.
import UIKit
class restultViewController: UIViewController {
#IBOutlet var someLabel: UILabel!
public var myText: String?
override func viewDidLoad() {
super.viewDidLoad()
self.parseData()
}
private func parseData(){
guard let unwrapedText = self.myText else {
//you didn't pass string
return
}
if let myInt = Int(unwrapedText) {
myInt = myInt - 1
self.someLabel.text = String(myInt)
} else {
//you string is not convertable to int
}
}
}
You Can just do this.
import UIKit
class restultViewController: UIViewController {
#IBOutlet var dxe: UILabel!
var LebelText = String()
let myInt = Int()
override func viewDidLoad() {
super.viewDidLoad()
steve()
}
func steve(){
var eq = Int(LebelText.text)
eq = eq - 1
dxe.text = String(eq)
}

OBD2Kit Swift example can't typecast, keep getting nil

Since there was no example code for using OBD2Kit and Swift I forked it into https://github.com/YannisDC/OBD2Kit and used it as a pod.
I translated some OBJ-C example code but can't seem to downcast the FLWiFiScanTool into the ELM327 type. Why do I keep getting nil?
import UIKit
import OBD2Kit
class ViewController: UIViewController, FLScanToolDelegate {
#IBOutlet weak var hostIpAddress: UITextField!
var scanTool: ELM327!
#IBOutlet weak var statusLabel: UILabel!
#IBOutlet weak var scanToolLabel: UILabel!
#IBOutlet weak var rpmLabel: UILabel!
#IBOutlet weak var speedLabel: UILabel!
#IBOutlet weak var tempLabel: UILabel!
var scanning = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.hostIpAddress.text = "192.168.0.10"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func scanButton(sender: UIButton) {
if !scanning {
startScan()
} else {
stopScan()
}
}
func startScan() {
if let scanTool = ELM327(host: self.hostIpAddress.text!, andPort: 35000) {
self.statusLabel.text = "Initializing..."
scanTool.useLocation = true
scanTool.delegate = self
scanTool.startScanWithSensors({() -> [AnyObject] in
dispatch_async(dispatch_get_main_queue(), {() -> Void in
self.statusLabel.text = "Scanning..."
self.scanToolLabel.text = scanTool.scanToolName
})
// let sensors: [AnyObject] = [ OBD2Sensor.SensorEngineRPM as! AnyObject,
// OBD2Sensor.SensorVehicleSpeed as! AnyObject,
// OBD2Sensor.SensorOxygenSensorsPresent as! AnyObject ]
let sensors: [AnyObject] = [ 0x0C,
0x0D,
0x13 ]
return sensors
})
self.scanTool = scanTool
print("So far succesfull")
scanning = !scanning
} else {
self.statusLabel.text = "Not working"
}
}
func stopScan() {
statusLabel.text = "Stopped"
let scanTool: ELM327 = self.scanTool
scanTool.cancelScan()
scanTool.sensorScanTargets = nil
scanTool.delegate = nil
scanning = !scanning
}
// MARK: - FLScanToolDelegate
func scanTool(scanTool: FLScanTool, sensor: FLECUSensor) {
var sensorLabel: UILabel? = nil
switch sensor.pid {
case OBD2Sensor.SensorEngineRPM:
sensorLabel = self.rpmLabel
case OBD2Sensor.SensorVehicleSpeed:
sensorLabel = self.speedLabel
default:
sensorLabel = self.tempLabel
}
self.showSensorValue(sensor, onLabel: sensorLabel!)
}
func showSensorValue(sensor: FLECUSensor, onLabel label: UILabel) {
let sensorValue: String = "\(sensor.valueStringForMeasurement1(false)) \(sensor.imperialUnitString)"
dispatch_async(dispatch_get_main_queue(), {() -> Void in
label.text = sensorValue
})
}
}
Edit 1:
I can already scan for the tool now since ELM327 is a FLWiFiScanTool and not the other way around. I can get the toolname so it's connecting but can't seem to get the sensors output.
I managed to figure it out. The expected sensors array should be one of NSNumbers so I casted the sensors UInt's to NSNumbers.
And I also missed the didUpdateSensor part in the scanTool function.
Make sure to use the metric system, this is somehow way more reliable in my case. (My car is using the metric system as well, maybe that's why.)
import UIKit
import OBD2Kit
class ViewController: UIViewController, FLScanToolDelegate {
var scanTool: ELM327!
#IBOutlet weak var statusLabel: UILabel!
#IBOutlet weak var scanToolLabel: UILabel!
#IBOutlet weak var rpmLabel: UILabel!
#IBOutlet weak var speedLabel: UILabel!
#IBOutlet weak var tempLabel: UILabel!
var scanning = false
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func scanButton(sender: UIButton) {
if !scanning {
startScan()
} else {
stopScan()
}
}
func startScan() {
if let scanTool = ELM327(host: "192.168.0.10", andPort: 35000) {
self.statusLabel.text = "Initializing..."
scanTool.useLocation = true
scanTool.delegate = self
scanTool.startScanWithSensors({() -> [AnyObject] in
dispatch_async(dispatch_get_main_queue(), {() -> Void in
self.statusLabel.text = "Scanning..."
self.scanToolLabel.text = scanTool.scanToolName
})
let sensors: [AnyObject] = [ OBD2Sensor.SensorEngineRPM as NSNumber, OBD2Sensor.SensorVehicleSpeed as NSNumber, OBD2Sensor.SensorOxygenSensorsPresent as NSNumber ]
return sensors
})
self.scanTool = scanTool
print("So far succesfull")
scanning = !scanning
} else {
self.statusLabel.text = "Not working"
}
}
func stopScan() {
statusLabel.text = "Stopped"
let scanTool: ELM327 = self.scanTool
scanTool.cancelScan()
scanTool.sensorScanTargets = nil
scanTool.delegate = nil
scanning = !scanning
}
// MARK: - FLScanToolDelegate
func scanTool(scanTool: FLScanTool!, didUpdateSensor sensor: FLECUSensor!) {
var sensorLabel: UILabel? = nil
switch sensor.pid {
case OBD2Sensor.SensorEngineRPM:
sensorLabel = self.rpmLabel
case OBD2Sensor.SensorVehicleSpeed:
sensorLabel = self.speedLabel
default:
sensorLabel = self.tempLabel
}
self.showSensorValue(sensor, onLabel: sensorLabel!)
}
func showSensorValue(sensor: FLECUSensor, onLabel label: UILabel) {
let sensorValue: String = "\(sensor.valueStringForMeasurement1(true)) \(sensor.metricUnitString)"
dispatch_async(dispatch_get_main_queue(), {() -> Void in
label.text = sensorValue
})
}
}

ViewController does not have a member named tipCalc

//
// ViewController.swift
// TipCalculator
//
// Created by Mathias Bakken on 6/28/15.
// Copyright (c) 2015 Mathias Bakken. All rights reserved.
//
I have 6-8 instances where I am receiving the error for not having the member tipCalc. I attempted to make an empty variable, but that only made things worse.
import UIKit
class ViewController: UIViewController {
#IBOutlet var totalTextField : UITextField!
#IBOutlet var servQualitySlider : UISlider!
#IBOutlet var foodQualitySlider : UISlider!
#IBOutlet var servQualityLabel : UILabel!
#IBOutlet var foodQualityLabel : UILabel!
#IBOutlet var resultsTextView : UITextView!
#IBAction func calculateTapped(sender : AnyObject){
tipCalc.total = Double((totalTextField.text as NSString).doubleValue)
let possibleTips = tipCalc.returnPossibleTips()
var results = ""
for (tipPct, tipValue) in possibleTips{
results += "\(tipPct)%: \(tipValue)\n"
}
resultsTextView.text = results
}
#IBAction func servQualityChanged(sender : AnyObject){
tipCalc.servQuality = Double(servQualitySlider.value)/100.0
refreshUI()
}
#IBAction func foodQualityChanged(sender : AnyObject){
tipCalc.foodQuality = Double(foodQualitySlider.value)/100.0
refreshUI()
}
#IBAction func viewTapped(sender : AnyObject){
totalTextField.resignFirstResponder()
}
let tipCalc = TipCalculatorModel(total: 33.25, foodQuality: 0.06, servQuality: 0.06)
func refreshUI(){
totalTextField.text = String(format: "%0.2f", tipCalc.total)
foodQualitySlider.value = Float(tipCalc.foodQuality) * 100.0
servQualitySlider.value = Float(tipCalc.servQuality) * 100.0
foodQualityLabel.text = "Food Quality 1-10 (\(Int(foodQualitySlider.value))%)"
servQualityLabel.text = "Service Quality 1-10 (\(Int(servQualitySlider.value))%)"
resultsTextView.text = ""
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
refreshUI()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I am getting a bunch of the same error messages saying "ViewController does not have a member named tipCalc"
I am also receiving the error "Use of unresolved identifier TipCalculatorModel"
How do I fix this issue? Thank you!
import Foundation
class TipCalculatorModel{
var total: Double
var foodQuality: Double
var servQuality: Double
var subtotal: Double{
get{
return total / (foodQuality + servQuality + 1)
}
}
init(total: Double, foodQuality: Double, servQuality: Double){
self.total = total
self.foodQuality = foodQuality
self.servQuality = servQuality
}
func calcTipWithTipPct(foodQuality: Double, servQuality: Double)->Double{
return subtotal * (foodQuality + servQuality)
}
func returnPossibleTips()->[Int:Double]{
let possibleTipsInferred = [0.15, 0.18, 0.20]
let possibleTipsExplicit:[Double] = [0.15, 0.18, 0.20]
var retval = [Int:Double]()
for possibleTip in possibleTipsInferred{
let intPct = Int(possibleTip*100)
retval[intPct] = calcTipWithTipPct(foodQuality, servQuality: servQuality)
}
return retval
}
}
I solved the issue by just pasting in the other module. Not a pretty fix. But it works. Thank you.

Resources