Could you help me with a following case:
When I try "eachPersonPays" to convert from Decimal to String, I got error "Argument type 'Decimal' does not conform to expected type 'CVarArg'".
When I confirmed to fix to "as CVarArg" I don't get "totalBill" calculated.
What should I do in line:
totalBill = String(format: "%.2", eachPersonPays)
so that I can get totalBill calculated.
#IBAction func calculatePressed(_ sender: UIButton) {
bill = billTextField.text!
if (Decimal(string: bill) != nil) == true {
let eachPersonPays: Decimal = (Decimal(string: bill)! * tip) / Decimal(string: numberOfPeople)!
totalBill = String(format: "%.2", eachPersonPays)
print(totalBill)
self.performSegue(withIdentifier: "goToResult", sender: self)
} else {
billTextField.text = "input bill amount"
P.S.
I hope I could explain properly what the problem I have.
The specifier of the numeric object # is missing: format: "%#.2"
By the way
if (Decimal(string: bill) != nil) == true
is horribly unswifty, there is Optional Binding
if let decimalBill = Decimal(string: bill),
let decimalNumberOfPeople = Decimal(string: numberOfPeople) {
let eachPersonPays = decimalBill * tip / decimalNumberOfPeople
let totalBill = String(format: "%#.2", eachPersonPays as CVarArg) // or as NSNumber
}
Related
I'm trying to format numbers in a UITextField consists of math equation string: "number + number".
At the moment I can type just a single number, then convert it to Double -> format with NSNumberFormatter -> convert back to String -> assign to textField.text:
The code:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
formatter.locale = .current
formatter.roundingMode = .down
let numberString = textField.text ?? ""
guard let range = Range(range, in: numberString) else { return false }
let updatedString = numberString.replacingCharacters(in: range, with: string)
let correctDecimalString = updatedString.replacingOccurrences(of: formatter.decimalSeparator, with: ".")
let completeString = correctDecimalString.replacingOccurrences(of: formatter.groupingSeparator, with: "")
guard let value = Double(completeString) else { return false }
let formattedNumber = formatter.string(for: value)
textField.text = formattedNumber
return string == formatter.decimalSeparator
}
Now I want to add a calculation functionality and display a simple math equation in a textField as "number + number", but each number should be formatted as shown above. Example (but without formatting):
I can't properly implement that. The logic for me was: track the String each time new char inserts -> if it has math sign extract numbers -> convert them to Double -> format with NSNumberFormatter -> convert back to String -> construct a new String "number + number".
The code I tried:
if let firstString = completeString.split(separator: "+").first, let secondString = completeString.split(separator: "+").last {
guard let firstValue = Double(firstString) else { return false }
guard let secondValue = Double(secondString) else { return false }
let firstFormattedNumber = formatter.string(for: firstValue)
let secondFormattedNumber = formatter.string(for: secondValue)
textField.text = "\(firstFormattedNumber ?? "") + \(secondFormattedNumber ?? "")"
// another try
if completeString.contains("+") {
let stringArray = completeString.components(separatedBy: "+")
for character in stringArray {
print(character)
guard let value = Double(character) else { return false }
guard let formattedNumber = formatter.string(for: value) else { return false }
textField.text = "\(formattedNumber) + "
}
}
But it's not working properly. I tried to search but didn't find any similar questions.
Test project on GitHub
How can I format the numbers from such a string?
Here is how I was able to solve my question:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
formatter.locale = .current
formatter.roundingMode = .down
//set of possible math operations
let symbolsSet = Set(["+","-","x","/"])
let numberString = textField.text ?? ""
guard let range = Range(range, in: numberString) else { return false }
let updatedString = numberString.replacingCharacters(in: range, with: string)
let correctDecimalString = updatedString.replacingOccurrences(of: formatter.decimalSeparator, with: ".")
let completeString = correctDecimalString.replacingOccurrences(of: formatter.groupingSeparator, with: "")
//receive math symbol user typed
let symbol = symbolsSet.filter(completeString.contains).first ?? ""
//receive number of symbols in a String. If user wants to type more than one math symbol - do not insert
let amountOfSymbols = completeString.filter({String($0) == symbol}).count
if amountOfSymbols > 1 { return false }
//receive numbers typed by user
let numbersArray = completeString.components(separatedBy: symbol)
//check for each number - if user wants to type more than one decimal sign - do not insert
for number in numbersArray {
let amountOfDecimalSigns = number.filter({$0 == "."}).count
if amountOfDecimalSigns > 1 { return false }
}
guard let firstNumber = Double(String(numbersArray.first ?? "0")) else { return true }
guard let secondNumber = Double(String(numbersArray.last ?? "0")) else { return true }
let firstFormattedNumber = formatter.string(for: firstNumber) ?? ""
let secondFormattedNumber = formatter.string(for: secondNumber) ?? ""
// if user typed math symbol - show 2 numbers and math symbol, if not - show just first typed number
textField.text = completeString.contains(symbol) ? "\(firstFormattedNumber)\(symbol)\(secondFormattedNumber)" : "\(firstFormattedNumber)"
return string == formatter.decimalSeparator
}
Here is the code:
#IBAction func calculatePressed(_ sender: UIButton) {
let tip = tipPercentSelected.currentTitle ?? "unknown"
print(tip)
}
'tipPercentSelected' here represents an amount of tips in % that can be chosen by the user, e.g. 20%. In the code this 'tipPercentSelected' if of type String.
I need to have 0.2 instead of 20% to be printed out to console when the relevant button is pressed. However, if 'tipPercentSelected' is converted into Int it gives nil
#IBAction func calculatePressed(_ sender: UIButton) {
let tip = tipPercentSelected.currentTitle ?? "unknown"
print(tip)
let tipConverted = Int(tip)
print(tipConverted)
}
What code do I need to get 0.2 instead of 20%?
Thanks.
You should use a NumberFormatter with style set to percent
let tipPercent = "20%"
let formatter = NumberFormatter()
formatter.numberStyle = .percent
if let tip = formatter.number(from: tipPercent) {
print(tip)
}
This prints 0.2
In your view controller it could be something like this
static private let formatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .percent
return formatter
}()
func calculatePressed(_ sender: UIButton) {
if let tip = tipPercentSelected.currentTitle, let tipConverted = Self.formatter.number(from: tip) {
print(tipConverted)
}
}
trying to assign label text to 2 each textField inputs
warning show up says cannot assign value of type Double to type string
any suggestions
#IBAction func percentage1button(_ sender: Any) {
let firstValue = Double(percentage1textField1.text!)
let secondValue = Double(percentage1textfield2.text!)
let outputValue = Double(firstValue! + secondValue!)
percentage1result.text = outputValue
}
I will also suggest you not to use force unwrap:
#IBAction func percentage1button(_ sender: Any) {
guard let val1 = Double(percentage1textField1.text ?? ""),
let val2 = Double(percentage1textfield2.text ?? "") else
{
return
}
let outputValue = val1 + val2
percentage1result.text = "\(outputValue)"
}
I converted text field string into a double to do calculations and then back to a string to output it on a label. I am now working with currency inputs so I need to convert it to a decimal rather than a double. Can someone help?
func calcTotal() {
let totalConv: Double? = Double(totalTextField.text!)
let tipConv: Double? = Double(tipTextField.text!)
guard totalConv != nil && tipConv != nil else {
return
}
let result = totalConv! * ((tipConv! / 100) + 1)
let output = String(format: "$ %.2f", result)
totalAmount.text = String(output)
}
You will just need to use Decimal(string:) initializer and NumberFormatter (currency style) to format your decimal value.
func calcTotal() {
guard
let totalConv = Decimal(string: totalTextField.text!),
let tipConv = Decimal(string: tipTextField.text!)
else { return }
let result = totalConv * ((tipConv / 100) + 1)
totalAmount.text = Formatter.currency.string(for: result)
}
extension Formatter {
static let currency: NumberFormatter = {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .currency
return numberFormatter
}()
}
I'm very basic to Swift and trying to convert a text value, multiply its value by 7 and print the output.
WHen I try to print the output I get "lldb"?
Why do I get this error?
#IBAction func findAge(sender: AnyObject) {
print(age.text!)
let enteredAge = Int(age.text!)
let catYears = enteredAge! * 7
print(String(catYears))
}
You should be checking if it can actually be converted to an Integer.
let enteredAge = Int(age.text!)
if enteredAge == nil{
//do nothing
}
else{
//multiply by 7
}