fatal error: unexpectedly found nil while unwrapping an Optional value Computation - ios

import UIKit
class ViewController: UIViewController {
#IBOutlet weak var yourScore: UITextField!
#IBOutlet weak var totalScore: UITextField!
#IBOutlet weak var labelText: UILabel!
#IBAction func buttonPressed(sender: AnyObject) {
let score1: Int = yourScore.text.toInt()!
let score2: Int = totalScore.text.toInt()!
let mistakes = score2 - score1
let scoreFinal = ((((score2 / 2) - mistakes)*23)/score2)+75
labelText.text = "\(scoreFinal)"
}
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.
}
}
Something is wrong with my code. Is it because of data types or something? When I load the application, it just opens fine but when the button is pressed, the app crashes.
http://i.stack.imgur.com/B2i5Z.png

You could safely unwrap the values with if let:
if let score1 = yourScore.text.toInt() {
if let score2 = totalScore.text.toInt() {
let mistakes = score2 - score1
let scoreFinal = ((((score2 / 2) - mistakes)*23)/score2)+75
labelText.text = "\(scoreFinal)"
} else {
// no valid score2
}
} else {
// no valid score1
}

While unwrapping, you can't just willy nilly use the values. Before unwrapping you have to check if the current value is nil. If it's not nil, then you can safely unwrap the text.

Related

error with type of string in swift 3

A print(user) shows what I need, but the label wont take it. I don't really understand.
Can someone explain what's wrong ?
Here is the printscreen
edited: here is the code :
import UIKit
class MainViewController: UIViewController {
#IBOutlet weak var etqRetards: UILabel!
#IBOutlet weak var etqBiens: UILabel!
#IBOutlet weak var etqSortie: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
//on récupère l'utilisateur courant.
let fm = FileManager.default
let urlRepDocuments = try! fm.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let url = urlRepDocuments.appendingPathComponent("user.plist")
if let dico = NSMutableDictionary.init(contentsOfFile: url.path){
if dico["email"] != nil {
let user = dico["email"] as! String
}
}
etqBiens.text = user
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func btnLocataires(_ sender: Any) {
}
#IBAction func btnBatiments(_ sender: Any) {
}
#IBAction func btnOutils(_ sender: Any) {
}
}
Here is the part where your code don't work anymore:
1: if let dico = NSMutableDictionary.init(contentsOfFile: url.path){
2: if dico["email"] != nil {
3: let user = dico["email"] as! String
4: }
5: }
5: etqBiens.text = user
userwill only be accessible on row 3, since it´s declared within that if-statement. What you need to do is to declare user globally so that you can access it and also declare it as a var to be able to change the value.
Do it like this instead:
import UIKit
class MainViewController: UIViewController {
#IBOutlet weak var etqRetards: UILabel!
#IBOutlet weak var etqBiens: UILabel!
#IBOutlet weak var etqSortie: UILabel!
var user = "" // declare user here
override func viewDidLoad() {
super.viewDidLoad()
//on récupère l'utilisateur courant.
let fm = FileManager.default
let urlRepDocuments = try! fm.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let url = urlRepDocuments.appendingPathComponent("user.plist")
if let dico = NSMutableDictionary.init(contentsOfFile: url.path){
if dico["email"] != nil {
user = dico["email"] as! String
}
}
etqBiens.text = user
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func btnLocataires(_ sender: Any) {
}
#IBAction func btnBatiments(_ sender: Any) {
}
#IBAction func btnOutils(_ sender: Any) {
}
}
I mean, to start off, user is not defined in the scope of the statement etqBiens.text...
If you want to copy the description of the user as a string, you can do so by saying user.description but I don't know how exactly that might be useful in the long run ¯\_(ツ)_/¯

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
})
}
}

Swift bad instruction error shopping list

I have a problem, Xcode gives me this error "EXC_BAD_INSTRUCTION(code=EXC_1386_INVOP,subcode==0*0)" while I'm trying to make my buttons delete indexes in my array, "shoppingList".
Please help me and tell me what i did wrong so i can improve later on.
//
// ViewController.swift
// ShoppingList
//
// Created by Petr Chrastek on 29/03/16.
// Copyright © 2016 ACS. All rights reserved.
//
class ViewController: UIViewController {
#IBOutlet weak var labelText: UILabel!
#IBOutlet weak var label0: UILabel!
#IBOutlet weak var label1: UILabel!
#IBOutlet weak var label2: UILabel!
#IBOutlet weak var label3: UILabel!
var shoppingList = ["eggs", "milk", "cake", "sugar"]
#IBAction func remove0(sender: UIButton) {
shoppingList.removeAtIndex(0)
}
#IBAction func remove1(sender: UIButton) {
shoppingList.removeAtIndex(1)
}
#IBAction func remove2(sender: UIButton) {
shoppingList.removeAtIndex(2)
}
#IBAction func remove3(sender: UIButton) {
shoppingList.removeAtIndex(3)
}
override func viewDidLoad() {
super.viewDidLoad()
let str: String? = shoppingList[0]
let str1: String? = shoppingList[1]
let str2: String? = shoppingList[2]
let str3: String? = shoppingList[3]
let count = shoppingList.count
labelText.text? = "you are missing \(count) items"
if str != nil {
label0.text? = "\(str)"
} else {
label0.text? = "empty"
}
if str1 != nil {
label1.text? = "\(str1)"
} else {
label1.text? = "empty"
}
if str2 != nil {
label2.text? = "\(str2)"
} else {
label2.text? = "empty"
}
if str3 != nil {
label3.text? = "\(str3)"
} else {
label3.text? = "empty"
}
// 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.
}
}
After you delete the first item from your list, shoppingList will only have 3 items in it, so accessing shoppingList[3] will crash (remember with 3 items only 0..<2 are valid.
The easiest way to resolve the problem is to use the following pattern so you're checking the count to make sure indices are valid before using them.
if shoppingList.count > 0 {
label0.text = shoppingList[0]
} else {
label0.text = "empty"
}
if shoppingList.count > 1 {
label1.text = shopingList[1]
} else {
label1.text = "empty"
}
I've made some additional changes as well, such as not pointless using string interpolation to turn a String into the same String, since [String][n] will always return a String (never a String?) there's no need to deal with the Optionals
You'll have similar problems (in fact, probably what you're running into now) when you try to:
shoppingList.removeAtIndex(3)
the second time, since 3 is no longer a valid index, instead, use:
if shoppingList.count > 3 {
shoppingList.removeAtIndex(3)
}

Flow Control in Xcode

For some reason, even if input a valid input, namely, an integer, it does seem to go into if statement in the function, #IBAction func guess(sender: UIButton){}. In other words, if I input 5, the console output will say "Please input a valid number." Not "you guessed to high" or "you guessed to low" or "you win!". Any suggestion on how to fix this?
The following is my code:
class ViewController: UIViewController {
//just some member variables. I don't think the problem is here.
#IBOutlet weak var inputField: UITextField!
#IBOutlet weak var output: UITextView!
var guesses : UInt = 0;
var number : UInt32 = 0;
var gameover = false;
let MAX_GUESSES = 8;
var possibleGuess : Int?
override func viewDidLoad() {
super.viewDidLoad()
number = generateNewNumber()
consoleOut("I'm thinking of a number...\n")
var possibleGuess : Int? = inputField.text.toInt()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//consoleOut here prints out stuff on the app.
func consoleOut(text : String) {
output.text = output.text + text;
}
func generateNewNumber() -> UInt32 {
return arc4random_uniform(100) + 1
}
func clearInput() {
output.text = ""
}
//here lies the problem. The control never seems to go inside of
//if let guess = possibleGuess{}
#IBAction func guess(sender: UIButton) {
if let guess = possibleGuess {
if UInt32(guess) > number {
consoleOut("\(guess): You guessed to high\n")
++guesses
}
else if UInt32(guess) < number {
consoleOut("\(guess): You guessed to low\n")
++guesses
}
else {
consoleOut("\(guess): You win!\n")
consoleOut("Go again? (y/n)")
guesses = 0
gameover = true
}
clearInput()
}
else {
clearInput()
consoleOut("Please input a valid number")
}
}
}
This is a very common mistake.
You declare a variable possibleGuess as optional Int instance variable, but later you declare a variable with the same name in viewDidLoad() whose scope is locally only within the viewDidLoad() method.
Solution : delete the var keyword in the viewDidLoad() method.
possibleGuess = inputField.text.toInt()
The explicit type annotation is not needed too as the type has been already defined.

Getting error while using NSBundle?

I used path to documents to link external file in app. But when I want to run the project on real iPhone, I replaced the path with NSBundle. Now I'm getting error because of NSBundle(I think) or something else. How can I debug it?
error in console: fatal error: unexpectedly found nil while unwrapping an Optional value
the whole code:
import UIKit
func assign() -> [String]{
let bundle = NSBundle.mainBundle()
let path = bundle.pathForResource("words", ofType: "txt")
let content = String(contentsOfFile: path!, encoding: NSUTF8StringEncoding, error: nil)//xcode marked that line with green
let newArray = content!.componentsSeparatedByString("\n")
return newArray
}
class ViewController: UIViewController, UITextFieldDelegate {
let newArray: [String] = assign()
#IBOutlet weak var textBox: UITextView!
#IBOutlet weak var firstInput: UITextField!
#IBOutlet weak var resultLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
firstInput.returnKeyType = .Search
firstInput.delegate = self
textBox.text = ""
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getFromPath() {
//getFromPath() func used to be in assign func.
var letters = firstInput.text
var res = search(set: newArray, letters: letters)
textBox.text! = ""
for element in res {
textBox.text = (textBox.text ?? "") + "\n" + "\(element)"
}
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
if firstInput.text == "" {
}
else {
getFromPath()
}
self.view.endEditing(true)
return false
}
func search(#set: [String], letters: String) -> [String] {
let result = filter(set) { item in
for char in letters {
if !contains(item, char) {
return false
}
}
return true
}
return result
}
}
It seems like you dont have that file in your bundle.
Make sure the file has been added to the target, check in the inspector.
Wrap critical initialization in
if let someObject = source as? someType
{
}
Drag your file to your project and place it together with your projects files. Make sure you select copy items if needed:
class ViewController: UIViewController {
let wordsUrl = NSBundle.mainBundle().URLForResource("words", withExtension: "txt")!
override func viewDidLoad() {
super.viewDidLoad()
var error: NSError?
if wordsUrl.checkResourceIsReachableAndReturnError(&error) {
println(true)
if let myString = String(contentsOfURL: wordsUrl, encoding: NSUTF8StringEncoding, error: &error) {
let myArray = myString.componentsSeparatedByString("\n")
println(myArray)
} else if let error = error {
println(error.description)
}
} else if let error = error {
println(error.description)
}
// 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.
}
}

Resources