Swift 2 Converting from String To Number - ios

I'm following the Stanford Videos for iOS development and I am using Xcode 7 with Swift 2.
I wrote the code from the video line by line, however I keep getting an error.
import UIKit
class ViewController: UIViewController
{
#IBOutlet weak var display: UILabel!
var userIsTyping = false
#IBAction func AppendDigit(sender: UIButton) {
let digit = sender.currentTitle!
if userIsTyping {
display.text = display.text! + digit
} else {
display.text = digit
userIsTyping = true
}
}
var operandStack = Array<Double>()
#IBAction func enter() {
userIsTyping = false
operandStack.append(displayValue)
}
var displayValue: Double {
get{
return NSNumberFormatter().numberFromString(display.text!)!.doubleValue
}
set (newValue){
display.text = "\(newValue)"
userIsTyping = false
}
}
}
At the line where I return
NumberFormatter().numberFromString(display.text!)!.doubleValue
I get an error of
Thread 1: EXC_BAD_INSTRUCTION(code=EXC_1386_INVOP,subcode=0x0)

A conversion can fail. The result can be nil. The "!" means "compiler, I am 100 percent sure that the result can never be nil, so if it is ever nil then please crash". Guess what, sometimes it is nil.
Use "if let".
PS. I think it is very, very unhealthy to take user interface elements (like the title of a button) and to assume they have certain values.

You are much better off substituting that return statement with a much simpler:
return Double(display.text!)!

let Number = (NSNumberFormatter().numberFromString(xtxt.text!)as! Double)
return Number

Related

Xcode finds nil in optional value and crashes Swift

I've been looking on this site for an answer to my question but no matter what I do my compiler still gives me the following error:
fatal error: unexpectedly found nil while unwrapping an Optional value
I don't know what is causing this seeing as I wrapped up all my code in an if statement to ensure that if the value submitted is nil it would print a message.
Here is the code:
#IBOutlet var textField: UITextField!
#IBOutlet var label4: UILabel!
#IBAction func buttonTapped(_ sender: Any) {
if textField.text != nil {
let textFieldInt: Int? = Int(textField.text!)
let convert = textFieldInt! * 7
label4.text = String(convert)
}
else {
label4.text = "Please enter a number!"
}
}
I've searched through similar questions and have understood a small amount about what is causing this error but I have yet to find a solution.
Could someone please help me?
I am using Xcode8 with the latest version of Swift.
You are force unwrapping using !. You need to do if let or guard let to unwrap because textFieldInt that you force wrapped may be nil.
You should use this code
if let textFieldText = textField.text {
if let textFieldInt = Int(textFieldText ){
let convert = textFieldInt * 7
label4.text = "\(convert)"
} else{
print("textFieldInt is nil")
}
}else{
print("text field's text is nil, not too likely")
}
The crash occurs due to textFieldInt is nil
the problem is that textField.text is not number-like String.
let textFieldInt: Int? = Int(textField.text!)
That's why textFieldInt is nil here:
let convert = textFieldInt! * 7
to solve this issue I would suggest to use this:
if let val = textField.text, let intVal = Int(val) {
let convert = intVal * 7
label4.text = String(convert)
} else {
label4.text = "Please enter a number!"
}
You declared textFieldInt as an optional Int? Thus, it's possible for it to be nil. The following will assure it's an Int
guard let textFieldInt = textField.text as? Int else {
//handle fail case
return
}
Try this:
#IBOutlet var textField: UITextField!
#IBOutlet var label4: UILabel!
#IBAction func buttonTapped(_ sender: Any) {
if textField.text != nil {
if let textFieldInt: Int? = Int(textField.text!){
let convert = textFieldInt! * 7
label4.text = String(convert)
}
}
else {
label4.text = "Please enter a number!"
}
}

Textfield as input in average function

I recently wanted to code an Average-Calculator.
My plan was to build a UITextField in which you can type Numbers separated by commas... By pressing the 'Calculate' button the App should calculate the Average of the Numbers above and give them out by setting a labeltext to the average.
So I wrote my average function and received this error message:
Can not convert value of type 'UITextField' to expected element type 'Double'.
This is my Code:
#IBOutlet var Input: UITextField!
#IBOutlet var Output: UILabel!
#IBAction func Calculate(sender: AnyObject) {
var grades:[Double] = [Input]
func average(nums: [Double]) -> Double {
var total = 0.0
for grade in nums{
total += Double(grade)
}
let gradesTotal = Double(nums.count)
let average = total/gradesTotal
return average
}
let Average = average(grades)
Output.text = "Average: \(Average)"
}
Can you help me with my idea?
Is there a better way to get an input?
You need to separate numbers to get that array if you do that:
you can pass "doubles" array to your average function
code to copypaste :)
var str = "1,2,3,4,5,6"
let stringsWithNumbers = str.componentsSeparatedByString(",")
let doubles = stringsWithNumbers.map { Double($0)! }
Please use lower camel case for variables...
In this line:
var grades:[Double] = [Input]
Input is an instance of UITextField, so you are trying to assign a single-element Array<UITextField> to Array<Double>. You see you cannot do such sort of things.
If you want to accept a text which contains Numbers separated by commas, you need to explicitly convert the text to [Double].
To simplify, let's just ignore the nil or non-numeric values.
Then you need to change your code as:
#IBOutlet var input: UITextField!
#IBOutlet var output: UILabel!
#IBAction func calculate(sender: AnyObject) {
var grades: [Double] = (input.text ?? "").componentsSeparatedByString(",").flatMap{Double($0)}
func average(nums: [Double]) -> Double {
var total = 0.0
for grade in nums{
total += Double(grade)
}
let gradesTotal = Double(nums.count)
let average = total/gradesTotal
return average
}
let averageValue = average(grades)
output.text = "Average: \(averageValue)"
}
The basic idea of this line:
var grades: [Double] = (input.text ?? "").componentsSeparatedByString(",").flatMap{Double($0)}
is well-described in Lu_'s answer. Mine is just a little safer version.
(Addition)
Some explanation about safety:
UITextFields property text is of type String?, so you should think it can be nil. Giving a default value for nil with ?? operator.
And using Double($0)! may crash your app, as Double($0) will return nil for non-numeric strings.
Writing these reminded me one more crash case.
When gradesTotal == 0, the code above will crash with division by zero.
(The default value does not work well for "safety" in the code above...)
So, one more step ahead to safety:
#IBAction func calculate(sender: AnyObject) {
var grades: [Double] = (input.text ?? "").componentsSeparatedByString(",").flatMap{
Double($0.stringByTrimmingCharactersInSet(.whitespaceCharacterSet()))
}
func average(nums: [Double]) -> Double? {
var total = 0.0
for grade in nums{
total += Double(grade)
}
let gradesTotal = Double(nums.count)
if gradesTotal > 0 {
let average = total/gradesTotal
return average
} else {
return nil
}
}
if let averageValue = average(grades) {
output.text = "Average: \(averageValue)"
} else {
output.text = "Average not available"
}
}
What you have to do is using Double(Input.text) instead of [Input]. Right now, you were trying to convert a UITextField to a double, which causes the error.
let textInput = txtInputView.text;
let components = textInput.componentsSeparatedByString(",");
let sum = 0.0;
for txt in components
{
sum = sum + Double(txt);
}
let avg = sum / components.count;
print(avg)
Here is the complete code if someone is interested :)
#IBOutlet var input: UITextField!
#IBOutlet var output: UILabel!
#IBAction func calculate(sender: AnyObject) {
var grades: [Double] = (input.text ?? "").componentsSeparatedByString(",").flatMap{
Double($0.stringByTrimmingCharactersInSet(.whitespaceCharacterSet()))
}
func average(nums: [Double]) -> Double? {
var total = 0.0
for grade in nums{
total += Double(grade)
}
let gradesTotal = Double(nums.count)
if gradesTotal > 0 {
let average = total/gradesTotal
return average
} else {
return nil
}
}
if let averageValue = average(grades) {
output.text = "Average: \(averageValue)"
} else {
output.text = "Average not available"
}
}
#IBAction func userTappedCalculate(sender: AnyObject) { view.endEditing(true)
}
I added the line #IBAction func userTappedCalculate(sender: AnyObject) { view.endEditing(true)
} to close the input TextField when you tap calculate...

Could not find an overload for “init” that accepts the supplied arguments - Stanford course work

I am trying to learn swift now and following the standard online and first lecture's work is to build a calculator. I followed exactly the same code but it failed to compile. code as follow:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var display: UILabel!
var UserIsInTheMiddleOfTyping = false
#IBAction func touchDigit(sender: UIButton) {
let digit = sender.currentTitle!
if UserIsInTheMiddleOfTyping {
let TextCurrentlyInDisplay = display.text!
display.text = TextCurrentlyInDisplay + digit
} else {
display.text = digit
}
UserIsInTheMiddleOfTyping = true
}
#IBAction func performOperation(sender: UIButton) {
UserIsInTheMiddleOfTyping = false
if let mathmaticalSymbol = sender.currentTitle{
if mathmaticalSymbol == "π" {
display.text = String(M_PI)
}
}
}
}
error message showed up on the line of display.text = String(M_PI).
it said "Could not find an overload for “init” that accepts the supplied arguments".
should be an easy question but I am new to Swift and couldn't figure it out.

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP,subcode = 0x0)

class ViewController: UIViewController {
#IBOutlet weak var label: UILabel!
var userIsInTheMiddleOfTypingNumber: Bool = false
#IBAction func appendDigit(sender: UIButton) {
let digit = sender.currentTitle!
if (userIsInTheMiddleOfTypingNumber) {
label.text = label.text! + digit
}
else {
label.text = digit
userIsInTheMiddleOfTypingNumber = true
}
}
}
I am currently creating a calculator app. For some reason, when I run the simulator and try to input some digits in, the siumulator freezes, and the error of bad_instruction appears on the line:
label.text = digit
How would I fix this situation?
Looks like you forgot to connect the label in the Storyboard with the outlet.
Looks like the currentTitle property is nil which results in a crash. You are force unwrapping the property without any nil check.
#IBAction func appendDigit(sender: UIButton) {
if let digit = sender.currentTitle {
if (userIsInTheMiddleOfTypingNumber) {
label.text = label.text! + digit
}
else {
label.text = digit
userIsInTheMiddleOfTypingNumber = true
}
}
}
OR
It could be the reason specified by #dasdom

Creating Random Number

I am new to the programming world and am trying my hand at a simple math app. Basically i want to app to create two random numbers and then add them together. I then put the answer in a text field where the app checks to see if the answer is right or wrong. I have created this and it works however I cannot get the numbers to regenerate after the answer is correct. Any direction you can give on this I would be much appreciative.
Here is the code.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.guess(self)
}
#IBOutlet weak var addend1: UILabel!
#IBOutlet weak var addend2: UILabel!
#IBOutlet weak var answer: UITextField!
#IBOutlet weak var response: UILabel!
//create numbers
let newaddend1 = arc4random() % 11
let newaddend2 = arc4random() % 11
#IBAction func guess(sender: AnyObject) {
//Convert Random Numbers to String to be displayed in labels
var firstNumber = String(newaddend1)
var secondNumber = String(newaddend2)
//convert the answer in the text field to an integer
var integer = answer?.text.toInt()
//Convert Strings to Ints so they can be added
var newFirstNumber = firstNumber.toInt()
var newSecondNumber = secondNumber.toInt()
//Add Numbers
var correctAnswer = (newFirstNumber! + newSecondNumber!)
//Display the numbers
addend1.text = firstNumber
addend2.text = secondNumber
//Print correct number to log for test
println(correctAnswer)
println(integer)
//check your answer agains the correct answer
if (integer != nil) {
if (integer == correctAnswer) {
response.text = "Correct! The Answer is \(correctAnswer)!"
} else {
response.text = "Wrongo Bongo the correct answer is \(correctAnswer)!"
}
} else {
response.text = "Please put in a number for your guess"
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//remove keyboard
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true)
}
func textFieldShouldReturn(textField: UITextField!) -> Bool {
answer.resignFirstResponder()
return true
}
}
You can initialize the variables outside of the IBAction to get class level variable declaration. Then immediately calculate new random numbers once the correct answer is generated:
let newaddend1 = 0
let newaddend2 = 0
#IBAction func guess(sender: AnyObject) {
//Convert Random Numbers to String to be displayed in labels
var firstNumber = String(newaddend1)
var secondNumber = String(newaddend2)
//convert the answer in the text field to an integer
var integer = answer?.text.toInt()
//Convert Strings to Ints so they can be added
var newFirstNumber = firstNumber.toInt()
var newSecondNumber = secondNumber.toInt()
//Add Numbers
var correctAnswer = (newFirstNumber! + newSecondNumber!)
//Display the numbers
addend1.text = firstNumber
addend2.text = secondNumber
//Print correct number to log for test
println(correctAnswer)
println(integer)
//check your answer agains the correct answer
if (integer != nil) {
if (integer == correctAnswer) {
response.text = "Correct! The Answer is \(correctAnswer)!"
let newaddend1 = arc4random() % 11
let newaddend2 = arc4random() % 11
} else {
response.text = "Wrongo Bongo the correct answer is \(correctAnswer)!"
}
} else {
response.text = "Please put in a number for your guess"
}
}

Resources