This question already has an answer here:
Input from UITextField connected from storyboard to Swift view controller file
(1 answer)
Closed 6 years ago.
How can I take an input value from the user with a text field and then use it to perform math functions in Swift?
I want to get a value from the user and then find the sine of that value.
Plus I want to take the input and covert it into radians.
Please help.
According to your comment, you have the textfield as an IBOutlet. I've added a button to get the value:
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var label: UILabel!
#IBAction func buttonPress(sender: AnyObject) {
guard let text = textField.text, value = Double(text) else { return }
label.text = String(sin(value))
}
The reason I've used guard is because if text is nil or if it's not a Double, it will just return, having done nothing (which is what I want). This way you don't have to worry about unexpected crashes when trying to calculate the value.
let sinValue = sin(Double("2")!)
is how you would process the string into a sin value
To get the text from the text field, you would need something like:
let sinValue = sin(Double(someTextField.text)!)
but you would first want to check that the text field had a value and validate that it was a number to prevent a crash.
//Initialize Textfied
var textField = UITextField(frame: CGRect(0, 0, 100, 100))
var sinNumber:Double = 0
//Now in your header (where it says class X:subclass list)
//maybe something like class Viewcontroller:UIViewController, UITextFieldDelegate
Add UITextFieldDelegate as above
Then you need to add the following function to determine when the user is done editing their TextField
func textFieldDidEndEditing(textField: UITextField) {
sinNumber = getSinOfInput(textField.text)
}
func getSinOfNumber(numbers:String) {
//If numbers is NOT a string full of numbers (it has characters), it should return nil
var num = Double(numbers)
if num != nil {
//Do login here to find the sin
num = ....
return num
}
else {
return 0
}
}
Related
I'm new to Swift. I managed to build an app which almost works, but I cannot get the last steps right. I would appreciate any help!
I wrote a code which displays a user-defined number of UILabels. In those labels, the contents of a [String] is displayed. Under the labels, there is the same number of UITextFields. The user should fill out these text fields, press the button and then see if what he filled out matches the labels.
All the labels, the text fields, and the button are made completely programmatically, so without using the storyboard. In the viewDidLoad there is all the code and this line:
myButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
Right under viewDidLoad there is this function which I found on this forum and I changed it a bit:
#objc func buttonAction(sender: UIButton!) -> [String] {
var a = 0
var userInput: [String] = Array()
while a < 4 {
if let myTextField = self.view.viewWithTag(a) as? UITextField {
let tekstInput = myTextField.text
userInput.insert(tekstInput!, at:a-1)
}
a = a + 1
}
return userInput
}
My problems:
The while-loop in the function shouldn't have 4 as the maximum, but a user-defined variable. But if I try to change function so that it expects that variable as an input, I get error messages in the myButton.addTarget line.
How do I read out the return in the viewdidload to add there the code to compare the user input with the original [String]?
You should consider the source of the user-defined input if you want to answer your question.
For instance, if you are willing to add an extra UITextField to retrieve your user input, then all you have to do is extract the value from that text field within your buttonAction(sender:) method and use it there. This translates roughly to the following
#objc func buttonAction(_ sender: UIButton) {
var a = 0
var userInput: [String] = Array()
guard let upperLimit = self.userInputTextField.text as? Int else {
return
}
while a < upperLimit {
if let myTextField = self.view.viewWithTag(a) as? UITextField {
let tekstInput = myTextField.text
userInput.insert(tekstInput!, at: a-1)
}
a = a + 1
}
}
Note that self.userInputTextField is the extra text field you should add in order to retrieve your user-defined input.
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!")
}
}
}
I am trying to set up questions with a text field for answers. Only after the exact answer has been entered can the next question be shown. I'm getting an error code with "if answerField == answers[currentQuestionIndex]" I believe I need to have allowances for what can be entered as answers. I'm stuck and could use some help in the right direction. thank you
#IBAction func answerField(sender: AnyObject) {
for index in 1...5 {
if answerField == answers[currentQuestionIndex] {
++self.currentQuestionIndex
if self.currentQuestionIndex == self.questions.count {
self.currentQuestionIndex = 0
}
}
}
}
let questions: [String] = ["From what is cognac made?", "What is 7+7?", "What is the capital of Vermont?"]
let answers: [String] = ["Grapes", "14", "Montpelier"]
override func viewDidLoad() {
super.viewDidLoad()
currentQuestion.text = questions[currentQuestionIndex]
}
answerField as you've shown it here is not a UITextField; it is a function. That is what the error is telling you: A function that takes AnyObject as a parameter and returns nothing ((AnyObject)->()) can't be compared to a String.
I think perhaps what you wanted to do was create an outlet (not an action) for your answer field:
#IBOutlet weak var answerField: UITextField! // Make sure you actually hook this up to your text field in the storyboard.
Then, listen for changes to the content of the text field:
override func viewDidLoad()
{
super.viewDidLoad()
answerField.addTarget(
self,
action: #selector(answerChanged(_:)),
forControlEvents: .EditingChanged)
currentQuestion.text = questions[currentQuestionIndex]
}
And then handle changes to your answer field text:
func answerChanged(sender: AnyObject)
{
if (answerField.text ?? "") == answers[currentQuestionIndex]
{
currentQuestionIndex = currentQuestionIndex + 1 < questions.count ? currentQuestionIndex + 1 : 0
currentQuestion.text = questions[currentQuestionIndex]
}
}
Or something along those lines.
If you answerField variable is UIText field then you need to use its text. The is an optional property so you also need to unwrap it
if (answerField.text ?? "") == answers[currentQuestionIndex]
From error code mentioned seems like you don't have variable answerField and you are trying to compare function itself to String, that doesn't make any sense
I'm building a calorie counter with two fields:
One: to enter calories per serving.
Two: to enter number of servings.
there is also a "remaining cal." label that starts at 2000. Every time a user entered a data set, the remaining calories should recalculate.
here is my code:
class ViewController: UIViewController, UITextFieldDelegate {
//MARK:Properties
#IBOutlet weak var enteredCalories: UITextField!
#IBOutlet weak var enteredServings: UITextField!
#IBOutlet weak var calorieCount: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
//Communicate user inputs into textFields through Delegate callbacks
enteredServings.delegate = self
//UITextFieldDelegate
func textFieldShouldReturn(textField: UITextField) -> Bool {
//Hide the keyboard
enteredServings.resignFirstResponder()
return true
}
//MARK:Actions
#IBAction func enterButton(sender: AnyObject) {
let startingCalories = Int(calorieCount.text!)!
if calorieCount != nil {
let calories = Int(enteredCalories.text!)!
let servings = Int(enteredServings.text!)!
let calculation = calories * servings
calorieCount.text = "\( startingCalories - calculation)"
enteredServings.text = " "
enteredCalories.text = " "
}
}
}
The first time through the process works fine. Enter any combo of cal./serving and #of servings and the app runs, and updates the remaining calorie counter label.
Whenever a second data set is entered into the text fields, I get an error telling me there is no value in one of my unwrapped optional values. Why am I getting this error if there is still a value for the cal.counter label, calories/serving field and #of servings field?
I'm brand new to programming and I know this is a question that has been asked many times. I understand what the error means, just not what it means for MY code, so I have no idea where to start to fix it.
Modify this method as below,
#IBAction func enterButton(sender: AnyObject) {
let startingCalories = Int(calorieCount.text!)!
if calorieCount != nil {
if let calories = Int(enteredCalories.text!)!, let servings = Int(enteredServings.text!)!{
let calculation = calories * servings
calorieCount.text = "\( startingCalories - calculation)"
enteredServings.text = " "
enteredCalories.text = " "
}
}
This would not give you a crash but not sure whether it would work as expected. Try checking the value by using breakpoints or try printing them on the console, using print().
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var display: UILabel!
var inMid = false
#IBAction func appendDigit(sender: UIButton) {
let digit = sender.currentTitle!
if inMid{
display.text = display.text! + digit
}else{
display.text = digit
inMid = true
}
}
var operandStack = Array<Double>()
#IBAction func enter() {
inMid = false
operandStack.append(displayValue)
println("operandStack = \(operandStack)")
}
var displayValue:Double{
get {
return NSNumberFormatter().numberFromString(display.text!)!.doubleValue
}
set{
display.text = "\(newValue)"
}
}
}
This is the part of code used in the latest Standford IOS 8 course using swift to build a calculator(Youtube address: https://www.youtube.com/watch?v=QLJtT7eSykg)
Every time I call enter() (press enter), a new number is supposed to be saved in a stack. For example: "8, enter()" --> {8}, "16, enter()" --> {8,16}.
I got confused about the computed property "displayValue" here. There is nothing assigned to the "newValue". If there is something like "displayValue = 8", then I know "newValue" is 8, and it all makes sense. But there is not such thing.
How come it still works?
(What I mean is not the name "newValue" itself,I know it is a default setting by Swift, instead, the missing of assigned value is the one that confuses me)
"newValue" is an implicitly defined variable in swift.
What he does is a very neat way of letting the label show the values of the double "displayValue" Every time displayValue is changed, the label is automatically updated with the newest (double) value.
Or when you write: displayValue = 45.0, the label will also show this value. Very handy when you constantly need to update textfield or labels with data you get from databases, rest interfaces, etc. What "newValue" does is taking the last "setter" value holding that.