swift 3.1 cannot pass decimals from UITextField - ios

in my View Controller I have a uitextfield where user can input decimals for some expense by pressing add button.
The issue: if I input Int like "100" everything works properly, but if I input "12,3" data is not accepted even if I'm converting the text in a Double
note : if I input a decimal, "print 1" values and stop, just like no data was set
note2: in my textfield I set to no correction and spellchecking due to xcodebug about textfield keyboard, but this change does not seem to influence the present issue
I declare:
var amount : Double!
my button:
#IBAction func addBillButton(_ sender: UIButton) {
print("button pressed 1")
guard self.dataInput.text != nil else {return}
amount = Double(self.dataInput.text!)
guard amount != nil else {return}
print("amount : \(amount!)")
dateShowed = myDatePicker.date as NSDate!
let dateShowedString = convertDateToString(dateToConvert: dateShowed as NSDate)
print("date : \(dateShowedString)")
if presentPickName != nil {
print("name is : \(presentPickName!)")
} else {
print("presentPickName is nil")
}
// guard presentPickData != nil else {return}
if presentPickTag != nil {
print("tag is : \(presentPickTag!)")
} else {
print("presentPickData is nil")
}
//func for saving in core data
// saveExpense(amountToSave: amount, amountDate: dateShowed as NSDate, owner: presentPickName, tag: presentPickTag)
resetViewForNextInput()
self.dataInput.resignFirstResponder()
print("button pressed 2")
}
my textfield in storyboard
EDIT SOLUTION:
in my button
guard let stringFromTxtField = self.dataInput.text else {return}
print(stringFromTxtField)
let myFormatter = NumberFormatter().number(from: stringFromTxtField) as! Double
print(myFormatter)
amount = myFormatter

It depends on locale, passing directly from text to number and viceversa should always be done by using a NumberFormatter. The number formatter knows the locale set in the settings and convert correctly your number.
For instance in italy decimal places are displayed with a ,,italian users find natural to input number like these 1,5 or 54,2 swift Double prints decimal like this 1.5 54.2 because the programming language requires numbers with a US format.
Thus a Double is not able to parse the string because it expect a number in this format.
Using a NumberFormatteryou can pass from the text to a correct number number because it know from the locale that the decimal separator in italy is ,.
Of course number formatters has a plenty of options, forcing the locale, forcing the decimal separator etc.
let double = NumberFormatter().number(from: "1,3") as! Double
This line of code with a locale set to Italy will get correctly a number of 1.3

Related

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.

Not able to check the condition on submit button swift

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

How do I sort Integer values typed into a TextField in Xcode?

I've just started to do some simple programming with Swift, things like building a simple calculator and stuff like that. Now I would like to create an app that allows me to sort a bunch of integer values which the user is typing into the TextField. Down here is what I've got so far. Could you please tell me where my mistake is?
class ViewController2: UIViewController {
#IBOutlet var randomNumbers: UITextField!
#IBOutlet var finalResult: UITextView!
#IBAction func SortNumbers(_ sender: UIButton) {
let sortedNumbers = Int[randomNumbers.text]
let sortedNubers = sortedNumbers.sort{$1>$2}
finalResult.text = String(sortedNumbers)
}
it's not the best answer you could get, but it might solves your problem:
#IBAction func sortNumbers(_ sender: UIButton) {
let stringWithNumbers = "1 23 12 4 5 12"
let sortedNumbers = stringWithNumbers.components(separatedBy: " ").flatMap { Int($0) }
let sortedNubers = sortedNumbers.sorted { $0 > $1 }
print(sortedNubers.description)
}
You're not converting it into an Int array properly. If we can assume that the input string is a comma-separated list with no spaces:
let sortedNumbers = randomNumbers.text.components(separatedBy: ",").map{ Int($0) ?? 0 }
components splits it into a string array using commas as a reference, and then map converts each element into an Int (and ?? 0 catches any invalid input and prevents it from being an array of optionals).
Also, for the sake of your sanity and that of anyone who might have to read your code later, avoid using nearly-identical variable names like sortedNumbers and sortedNubers. If you need to use multiple variables for the same data, make their differences more descriptive (for instance, the first one should probably be unsortedNumbers in this case).
Your mistake is in trying to treat a single string as if it were an array of numbers. You're missing two steps in there:
Parsing: Take the string that the user has typed and turn it into numbers
Formatting: Take the stored numbers and turn them back into a string to display
Lurking in that first step is the possibility that the user has not actually typed in integers. An approach that just ignores non-integer input would look like:
#IBAction func sortTextAction(_ sender: UIButton) {
guard let text = randomNumbers.text else {
finalResult.text = "" // clear out - no result on empty input
return
}
// Parse String -> [Int]:
// Split into words, then turn words into Ints,
// while discarding non-Int words
let words = text.components(separatedBy: CharacterSet.whitespacesAndNewlines)
let numbers = words
.map({ Int($0) }) // String -> Int?
.flatMap({ $0 }) // discard any nil values
let sorted = numbers.sort()
// Format [Int] -> String: glue the sorted Ints together with a space between each
finalResult.text = sorted
.map({ String(describing: $0 }) // Int -> String: turn 1 into "1"
.joined(separator: " ") // [String] -> String: turn [1, 2, 3] into "1 2 3"
}
}
Lurking behind both of these is localization: What one locale writes as "1,000" might be "1 000" or "1.000" elsewhere. For that, you'd pull in NumberFormatter to handle the conversions in a locale-aware way.

Cannot call value of non function type SKShapeNode

I keep trying to fix this error and trying to make the character contain in the row which will be an int.
func isRightTileAt(location:CGPoint) ->Bool {
//as shape node so we can get fill
var currentRect = self.atPoint(location) as! SKShapeNode
//get the 10th character which will contain the row and make it an int
// let rowOfNode = Int(currentRect.name![10]) //error(tried both of these)
var rowOfNode = Int(currentRect(name[10])) //error
//flip position is used for the row index below the screen to flip it to the top.
var currentRow = self.flipPosition + 1
var currentRowOfClick = self.flipPosition
//we reuse the flip position because it hasn't flipped yet but it normally contains the right row.
//because flip position happens after this check so it won't be sent back around yet
if self.flipPosition == 5 {
currentRowOfClick = 0
}
//if they are at least on the right row
if rowOfNode == currentRowOfClick && currentRect.fillColor.hash == 65536{
return true
}
return false
}
There are several challenges accessing the characters of the name property of SKNode or an SKNode subclass (such as SKShapeNode).
First, since name is a String?, it needs to be unwrapped.
guard let string = self.name else {
return
}
Second, you can't access the characters of a String with an Int subscript; you'll need to use a String.Index.
// Since Swift is zero based, the 10th element is at index 9; use 10 if you want the 11th character.
let index = string.index(string.startIndex, offsetBy: 9)
// The 10th character of the name
let char = string[index]
Third, you can't directly convert a Character to an Int. You'll need to convert the character to a String and then convert the string to an Int.
let rowString = String(char)
// Unwrap since Int(string:String) returns nil if the string is not an integer
guard let row = Int(rowString) else {
return
}
At this point, row is the 10th character of name converted to an Int.
Alternatively, you can implement the above as an extension
extension String {
func int(at index:Int) -> Int? {
let index = self.index(self.startIndex, offsetBy: index)
let string = String(self[index])
return Int(string)
}
}
and use it with
guard let name = self.name, let row = name.int(at:9) else {
return
}

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

Resources