2

When I enter a value in the UiTextField and press add button the app works perfectly fine,but when I don't enter a value in the UiTextField, then press the add button the whole app crashes. can someone please help me and show me the light.Thank you in advance and good wishes for you and your family.

This is my code

import UIKit

class ViewController: UIViewController,UITextFieldDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.textFild.delegate = self

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    @IBOutlet var textFild: UITextField!

    @IBAction func ButtonAwesome(sender: AnyObject) {



        let value:Double = Double(textFild.text!)!


        let sum:Double = value - 1;



        let alert = UIAlertController(title: "km", message:  "\(sum)", preferredStyle: UIAlertControllerStyle.Alert)
        alert.addAction(UIAlertAction(title: "Exit", style: UIAlertActionStyle.Default, handler: nil))
        self.presentViewController(alert,animated: true, completion: nil)



    }


    func textField(textField: UITextField,shouldChangeCharactersInRange range: NSRange,replacementString stringer: String) -> Bool
    {

        if (textField.text == "" && (stringer == ".")) {
            return false;
        }


        let countdots = textField.text!.componentsSeparatedByString(".").count - 1

        if countdots > 0 && stringer == "."
        {
            return false
        }


        return true
    }




}
Nata Mio
  • 2,168
  • 3
  • 22
  • 46
Jenny
  • 45
  • 7

3 Answers3

2

A more robust solution would be to use the nil coalescing operator to assert that the initialization of value never fails.

@IBAction func ButtonAwesome(sender: AnyObject) {
    let value = Double(textFild.text ?? "0") ?? 0
    let sum:Double = value - 1;

    let alert = UIAlertController(title: "km", message:  "\(sum)", preferredStyle: UIAlertControllerStyle.Alert)
    alert.addAction(UIAlertAction(title: "Exit", style: UIAlertActionStyle.Default, handler: nil))
    self.presentViewController(alert,animated: true, completion: nil)
}

This is valid for any of the following "unexpected" values of textField.text: nil, "" (empty) or some character that cannot be used to initialize a Double type variable (e.g. "a"). For all these cases, value is give a value of 0.


As an example, consider the following comparisons between a safe and an un-safe way of solving your initial runtime exception.

We first look at the dangers of forcibly unwrapping optionals - not a safe solution. What if textField.text contains nil or an non-numerical character, e.g. "a"? Result:

var myTextFieldText : String? = nil

/* Example 1: nil value causes runtime error */
if myTextFieldText != "" { // this is 'true' -> enter if closure
    let value:Double = Double(myTextFieldText!)!
    /* this will fail at run time since we are forcibly (un-safely)
       unwrapping an optional containing 'nil'                           */
}

/* Example 2: non-numeric string character causes runtime error */
myTextFieldText = "a"
if myTextFieldText != "" { // this is 'true' -> enter if closure
    let value:Double = Double(myTextFieldText!)!
    /* this will fail at run time since we cannot initalize a
       Double with a string value "a", hence 'Double(myTextFieldText!)'
       returns nil, but since we've appended '!', we, like above,
       forcibly tries to unwrap this optional of value nil              */
}

You should, generally, always use conditional unwrapping of optionals, to avoid encountering a nil value when forcibly unwrapping optionals, the latter leading to a runtime error.

A more robust version of the example above, making use of the nil coalescing operator:

myTextFieldText = nil

let valueA = Double(myTextFieldText ?? "0") ?? 0 // 0
/* OK, Double(myTextFieldText ?? "0") = Double("0") = 0                  */

myTextFieldText = "a"
let valueB = Double(myTextFieldText ?? "0") ?? 0 // 0
/* OK, Double(myTextFieldText ?? "0") = Double("a") = nil (fails)
    => use rhs of outer '??' operator: nil ?? 0 = 0                      */

For an alternative method, where you extend UITextField to cover your string to numerical type conversion needs, see Leos neat answer in the following thread:

The thread also contains some other valuable insights w.r.t. reading text as numerical values from UITextField instances.


Finally, when dealing with String to Double value conversion, it might be appropriate to use a fixed precision w.r.t. number of decimal digits in your resulting Double value. For a thorough example of how to do this using NSNumberFormatter and extensions, see:

Community
  • 1
  • 1
dfrib
  • 70,367
  • 12
  • 127
  • 192
  • I am using Decimal pad so I don't need to worry about strings. – Jenny Jan 10 '16 at 13:47
  • @Jenny The user can paste text – Leo Dabus Jan 10 '16 at 14:07
  • @Jenny you should always strive to keep your code safe, even against unexpected events that, at first glance, should not possibly occur. This is especially true if the code for the safe way of performing some task is equivalently complex as the code for performing the task possibly un-safe, as is the case in, e.g., this specific example. – dfrib Jan 10 '16 at 16:30
  • 1
    @LeoDabus thanks! I'll edit that link into the answer. – dfrib Jan 10 '16 at 16:31
  • @dfri for inputting doubles it is better if you specify fixed width fraction digits check this one for inputing currency http://stackoverflow.com/a/29783546/2303865 – Leo Dabus Jan 10 '16 at 16:51
  • 1
    @LeoDabus That's really neat! You frequent extension "fixes" are really neat and clever, thanks for giving me this feedback, I learn a lot from these! :) – dfrib Jan 10 '16 at 17:07
1

Please replace your buttonAwesome method with the following code where you check if textfield is not empty, this will work if textfield has a value:

@IBAction func ButtonAwesome(sender: AnyObject) {

    if textFild.text != "" {

    let value:Double = Double(textFild.text!)!


    let sum:Double = value - 1;


    let alert = UIAlertController(title: "km", message:  "\(sum)", preferredStyle: UIAlertControllerStyle.Alert)
    alert.addAction(UIAlertAction(title: "Exit", style: UIAlertActionStyle.Default, handler: nil))
    self.presentViewController(alert,animated: true, completion: nil)

    }

}
Nata Mio
  • 2,168
  • 3
  • 22
  • 46
0

Since textfield.text is an optional value and as in your case textfield can or cannot have text. So you should test for optional as give below.

if let textIsAvailable = textfield.text
{
        print("Text \(textIsAvailable)")
}

Note : The reason for your crash is you are trying to access value which actually doesn't have any value.

VIP-DEV
  • 221
  • 1
  • 6