Not able to check the condition on submit button swift - ios

Short description :
I am getting one value called UserValue. This will come from one response.And i have one Confirm button press method. In that each time i need to check whether the user entered amount is greater then UserValue amount.
but some time the value will be UserValue will be nill.That time it should not check whethere entered amount in text filed is greater than UserValue
Now here my code :
#IBAction func confirmButnClicked(_ sender: Any) {
print(UserValue)
let Mvalue = Double((UserValue.formattedAmount()))
let stringValue = Int(Mvalue!)
if doubleValue < stringValue {
DialogUtils.showMessageWithOk(controller: self, message: "Maximum Value is : \(UserValue)")
}
}
Its working fine when i got some value in UserValue but when i get nill value here its crashing...How can i handle this:
let stringValue = Int(Mvalue!) // crash here
Thanks in advance !!

You are forcefully unwrapping the nil, Due to that its crashing.
Check the UserValue is nil or not. If not nil then do the comparison
#IBAction func confirmButnClicked(_ sender: Any) {
print(UserValue)
if let UserValue = UserValue {
if let Mvalue = Double((UserValue.formattedAmount())) {
if let stringValue = Int(Mvalue) {
if doubleValue < stringValue {
DialogUtils.showMessageWithOk(controller: self, message: "Maximum Value is : \(UserValue)")
}
}
}
}
}

Instead of force casting MValue to Int you will get error when MValue is nil or anyother type content except integer
let stringValue = Int(Mvalue!)
use like below
if let stringValue = Int(Mvalue) {
//Now it prints your perfect unwrapping value
if doubleValue < stringValue {
DialogUtils.showMessageWithOk(controller: self, message: "Maximum Value is : \(UserValue)")
}
}

Related

How to prevent iOS app from crashing due to empty textfields?

I need to figure out a solution to prevent the app from crashing when a value is not entered in a textfield. The idea is if the textfield is empty (nil), the value of that textfield will then equal zero. Below I have copied my code:
let taxPercentDou:Double = Double(taxnosign2!)!
Anyone has any suggestions?
You need to stop force unwrapping optionals with the exclamation ! sign:
let b:Double = Double(rent.text!)!// Rent
If rent.text is nil or contains non-numeric text, your app will crash.
You can check for nil and replace it with "0" using the null coalescing operator:
rent.text ?? "0"
You can pass that into the Double initializer like this:
Double(rent.text ?? "0")
However, this will return nil if rent.text contains non-numeric text. You can use the null coalescing operator again to handle this:
let b: Double = Double(rent.text ?? "0") ?? 0.0
You could take this one step farther and write a simple utility method to make it easier to use for all your fields:
func convertToDouble(text: String?) -> Double {
return Double(text ?? "0") ?? 0.0
}
And call it like this:
let b = convertToDouble(rent.text)
Please find the below code. It Might Help you.
static func isNull(aString: AnyObject?) -> Bool
{
//Check for null
if(aString is NSNull){
return true
}
if(aString == nil){
return true
}
let x: AnyObject? = aString
//if string is nsnumber , convert it into string and check
if(aString is NSNumber){
var aString1 : String? = ""
aString1 = String(describing: aString)
return self.isStringEmpty(aString: aString1!)
}
if let aString1 = x as? String
{
return self.isStringEmpty(aString: aString1)
}
else
{
return true
}
}

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

I know there are answers available regarding this exception but nothing is working for me.
My code was working fine where I have to convert the text of a textfield into Int, but now I noticed that when I enter more than 10 characters it crashes.
I have set character limit of those text fields to 11, but it is crashing on the last number with the error: Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
Here is the code
#IBAction func Qty_EndEdit(_ sender: Any) {
print("For Total Cost")
if QtyText.text != ""{
if UnitPriceText.text != "" {
TotalCostText.text = String((QtyText.text?.numberValue)! * (UnitPriceText.text?.numberValue)!)
}
}
}
#IBAction func UnitPrice_EndEdit(_ sender: Any) {
print("For Total Cost")
if QtyText.text != ""{
if UnitPriceText.text != "" {
TotalCostText.text = String((QtyText.text?.numberValue)! * (UnitPriceText.text?.numberValue)!)
// CRASHING ON THE ABOVE LINE
}
}
}
extension String {
var numberValue:Int? {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
return formatter.number(from: self) as! Int
}
}
Your crash is related to the fact that Int multiplication cannot handle such numbers, use Double.
Both of your actions do the same thing, try to place code that will be reused inside a func.
You also need to look at optionals and how to use them. Here's an example.
func updateTotalCost() {
if let quantity = Double(QtyText.text ?? ""),
let unitPrice = Double(UnitPriceText.text ?? "") {
TotalCostText.text = String(quantity * unitPrice)
} else {
// ???
TotalCostText.text = ""
}
}
#IBAction func Qty_EndEdit(_ sender: Any) {
updateTotalCost()
}
#IBAction func UnitPrice_EndEdit(_ sender: Any) {
updateTotalCost()
}
I'll dissect some of it:
QtyText.text ?? "" -> If QtyText.text is nil, replace it with an empty string, otherwise use the value in QtyText.text
Double(QtyText.text ?? "") -> Build an Double from aString, which is guaranteed non-nil (since we forced it to be an emptyString`, even in the case the QtyText.text was nil)
This Double() constructor may, itself, return nil if the string passed to the constructor does not evaluate to a valid Double (for example, the String "abcd" cannot evaluate to an Double). Therefore, we wrap this in an if let statement to protect ourselves against the Double() constructor failing to build an Double from our String:
if let quantity = Int(QtyText.text ?? "")
This is telling the compiler:
Only evaluate this as true if what I'm placing in the quantity variable is not nil.
Finally, we chain two if statements with a comma:
if let quantity = Int(QtyText.text ?? ""),
let unitPrice = Int(UnitPriceText.text ?? "") {
Inside this part of the if statement, we'll be guaranteed that quantity and unitPrice both are valid Doubles , and that we can perform the calculation.
I’m not sure you’ll be please with the result of String(myDoubleNumber) but then you should look into number formatting to get what you want.

Cannot invoke initializer for type 'Double' with an argument list of type '(String?)' - Swift Storyboard

Getting this error trying to convert to a double. Any ideas why?
class ViewController : UIViewController {
#IBOutlet var textField : UITextField!
#IBOutlet var answerButton : UIButton!
#IBOutlet var fahrenheitLabel : UILabel!
#IBAction func tempFieldEditingChange(_ textField: UITextField) {
fahrenheitLabel.text = textField.text
}
#IBAction func showAnswer (_ sender : UIButton) {
let temperatures = ["hot","warm","cool","cold"]
let thresholds : [Double] = [80,60,40,0]
let temperature = Double(textField.text) //<-- (ERROR)
for (i,threshold) in thresholds.enumerated() {
if temperature >= threshold {
fahrenheitLabel.text = temperatures[i]
break
}
}
}
}
Trying to take user input of a temperature and spit out a label with hot warm cool or cold. I know theres something I'm missing please help! Thank you.
textField.text is an optional String, so you need to unwrap it before passing the value to a function that doesn’t accept an optional, such as the Double(_ String:) initialiser.
I would use a guard statement to do so. The string may not be able to be parsed as a Double, so that initialiser also returns an optional, which needs to be unwrapped.
#IBAction func showAnswer (_ sender : UIButton) {
guard let text = textField.text else {
return
}
let temperatures = ["hot","warm","cool","cold"]
let thresholds : [Double] = [80,60,40,0]
if let temperature = Double(text) {
for (i,threshold) in thresholds.enumerated() {
if temperature >= threshold {
fahrenheitLabel.text = temperatures[i]
break
}
}
}
}
}
The UITextField.text property returns an optional String? type. The Double's initializer requires a regular String.
To use the text property, you must first "unwrap" it, i.e. transform it from an optional value into a non-optional. There are several ways to do it:
Forced unwrapping
If you are certain, that the text property is not nil, you may forcibly unwrap it. Be mindful though, as when you try to forcibly unwrap a nil value, your app will crash.
if textField.text != nil {
let temperature = Double(textField.text!)
}
In this case, the text property should never be nil. However, if there were some code changing the property inside the if statement and before the line where the property is forcibly unwrapped, the forced uwrapping might crash.
Optional binding (the preferred way)
This method lets you unwrap the property safely by binding its value to another constant/variable, and once the value is bound, it can be freely used without the possibility of it becoming nil.
if let temperatureValue = textField.text {
let temperature = Double(temperatureValue)
}
The unwrapped temperatureValue constant will remain available and non-optional throughout the whole if-let scope, meaning that up to the closing brace of the if-let statement you can use it freely and will be gone outside the statement's braces. If the textField.text is nil, the inside of the statement's braces will never be executed.
Instead of if-let, you might use the guard-let statement:
guard let temperatureValue = textField.text else {
return
}
let temperature = Double(temperatureValue)
Notice however that any guard statement requires the function to return if the statement fails, but the unwrapped value can be accessed normally in the rest of the function, not only in a closing braces of a statement, like with if-let.
Last thing: the Double's initializer that takes a String also returns an optional value - so in order to use it (e.g. compare to other Double values), you must unwrap it as well:
if let temperature = Double(temperatureValue) {
// compare "temperature" to other Double values
}
This should work with if let way
let atextField = UITextField(frame: .zero)
atextField.text = "55.9"
if let d = Double(atextField.text!) {
print(d)
} else {
print("no")
}
You need to unwrap .text. Here is how I would do it:
class ViewController : UIViewController {
#IBOutlet var textField : UITextField!
#IBOutlet var answerButton : UIButton!
#IBOutlet var fahrenheitLabel : UILabel!
#IBAction func tempFieldEditingChange(_ textField: UITextField) {
fahrenheitLabel.text = textField.text
}
#IBAction func showAnswer (_ sender : UIButton) {
guard let text = textField else {
fatalError("Handle case when textField.text is nil") // TODO
}
guard let temperature = Double(textField) {
fatalError("Handle case when textField.text is nonnil but not a double") // TODO
}
switch temperature {
case ..<40: textField.text = "cold"
case 40..<60: textField.text = "cool"
case 60..<80: textField.text = "warm"
case 80...: textField.text = "hot"
default: fatalError("Non-exhaustive temperature ranges!")
}
}
}

Better way to check for a Int in a textbox

I am learning Xcode and creating a very simply program with a textbox(txt box) in which the user enters a value, a button (btnCalc) that performs a calculation, and a label (lblcalcdnumber) that shows the calc'd number. I have already selected Number Pad to be displayed as the dropdown keyboard but i want to check to make sure that if they enter anything other than a number that nothing happens. The code i have works but i feel like there should be a cleaner solution. Essential i want them to only enter Integers in the textbook.
// Mark: Actions
#IBAction func btnCalc(sender: UIButton) {
// let txtbox text beome int
let number1 = Int(txtBox.text!)
// let possibleInt convert mystring to int to check for nil, txtbox becomes OPTIONAL
let possibleInt = Int(txtBox.text!)
let number = 25
if possibleInt != nil {
let combinednumber = "\(Int(number1!) * number)"
lblCalcedNumber.text = combinednumber
}
else {
txtBox.text = ""
txtBox.placeholder = "Please Enter a Valid Number"
}
}
You can use if and let together to create an optional. If the value is not nil it will cast to possibleInt, otherwise, it will evaluate as false.
#IBAction func btnCalc(sender: UIButton) {
if let possibleInt = Int(txtBox.text!) {
let combinednumber = "\(possibleInt * 25)"
lblCalcedNumber.text = combinednumber
}
else {
txtBox.text = ""
txtBox.placeholder = "Please Enter a Valid Number"
}
}
Your variables 'number1' and 'possibleInt' have the same value, so you only need one of them for this section of code. Since 'number' is only used once it would be better to use the value itself rather than create a variable for it, however, if you use it elsewhere keep it as a variable so you only need to change your code in one spot. If you weren't using the possibleInt/number1 value inside the if statement, you could be even more efficient by doing if Int(txtBox.text!) != nil. Try this:
// Mark: Actions
#IBAction func btnCalc(sender: UIButton) {
let possibleInt = Int(txtBox.text!)
if possibleInt != nil {
let combinednumber = "\(possibleInt * 25)"
lblCalcedNumber.text = combinednumber
}
else {
txtBox.text = ""
txtBox.placeholder = "Please Enter a Valid Number"
}
}

Calling/messaging code crashing?

I have buttons that when pressed, will call/message a number from an array. i.e. button1 will call the number at index 0 of the array, button2 at index 1, etc.. For some reason whenever the number from the array contains a format other than xxx-xxx-xxx it crashes (i.e. (xxx) xxx-xxx). And yet, the log gives me the following error even though the array isn't nil:
Anyone know why this is happening?
Here is the code for everything:
import UIKit
import AddressBook
var contactInfo: [String] = []
[...]
override func viewDidLoad() {
super.viewDidLoad()
//this is the function that grabs the array from an app group
setUpCallMessageButtons()
[...]
callButton1.addTarget(self, action: "call:", forControlEvents: UIControlEvents.TouchUpInside)
}
func call(sender:UIButton!)
{
if (sender == callButton1) {
println("\(contactInfo)")
var url:NSURL? = NSURL(string: "tel:\(contactInfo[0])")
self.extensionContext?.openURL(url!, completionHandler:{(success: Bool) -> Void in
})
}
}
func setUpCallMessageButtons(){
let appGroupID = "**redacted**"
let defaults = NSUserDefaults(suiteName: appGroupID)
contactInfo = (defaults!.objectForKey("contactInfo") as! [String])
println("\(contactInfo)")
//This is gives the log down below. As you can see, none are nil.
}
Buttons 1,2 and 5 work while 3 and 4 always crash.
My guess is that if the phone number isn't formatted correctly, the call to convert it to an NSURL is failing and returning nil.
You probably need to wrap your call to openURL in an optional binding ("if let") block:
var url:NSURL? = NSURL(string: "tel:\(contactInfo[0])")
if let url = url
{
self.extensionContext?.openURL(url!,
completionHandler:
{
(success: Bool) -> Void in
}
}
else
{
println("Phone number \(contactInfo[0]) is not in a valid format")
}
You might want to strip away parenthesis from your phone number before trying to create your URL. A simple way would be to use the NSString method stringByReplacingOccurrencesOfString:withString:.
Here's a little storyboard - which shows you where the nil is coming from
Unexpectedly found nil means there is a variable which is expected to be non-nil but at run time was nil
This is the line of code that is causing the issue
self.extensionContext?.openURL(url!, completionHandler:{(success: Bool)
It expects url to be non-nil (i.e. the !) but it is definitely nil (see image)
If this data comes from the user or from the internet, you might want a method to strip away all non-numeric characters. Something like this (from a working playground I just banged out) :
import UIKit
func digitsOnly(#fromString: String) -> String
{
var workString = NSMutableString(string: fromString)
let digitsSet = NSCharacterSet.decimalDigitCharacterSet()
var index: Int
for index = count(fromString)-1; index>=0; index--
{
if !digitsSet.characterIsMember(workString.characterAtIndex(index))
{
workString.deleteCharactersInRange(NSRange(location:index, length:1))
}
}
return workString as String
}
let testString = "(555) 111-2222"
let result = digitsOnly(fromString:testString)
println("digitsOnly(\"\(testString)\") = \"\(result)\" ")
This displays:
digitsOnly("(555) 111-2222") = "5551112222"
Edit:
Or alternately a more Swift-like version of the same function:
func digitsOnly(#fromString: String) -> String
{
var result = String()
let digitsSet = NSCharacterSet.decimalDigitCharacterSet()
for char in fromString
{
if digitsSet.characterIsMember(char as unichar)
result += char
}
}
EDIT #2:
You can increase the set of characters that is left in place by changing the character set you use. Replace the line
let digitsSet = NSCharacterSet.decimalDigitCharacterSet()
With
let digitsSet = NSCharacterSet(charactersInString: "0123456789+-")
To preserve "+" signs and dashes. (Edit the string to include the characters you need.)

Resources