Преобразование строки в float в Swift от Apple
Я пытаюсь преобразовать числа, взятые из UITextField, которые, я полагаю, на самом деле являются строками, и преобразовать их в float, чтобы я мог их умножить.
у меня есть два UITextfield
s, которые объявляются следующим образом:
@IBOutlet var wage: UITextField
@IBOutlet var hour: UITextField
когда пользователь нажимает UIButton, я хочу рассчитать заработную плату пользователя, но я не могу, так как мне нужно сначала преобразовать их в поплавки, прежде чем я смогу их использовать.
Я знаю, как преобразовать их в целое, делая это:
var wageConversion:Int = 0
wageConversion = wage.text.toInt()!
однако я понятия не имею, как преобразовать их в поплавки.
16 ответов
Swift 2.0+
теперь Swift 2.0 вы можете просто использовать Float(Wage.text)
возвращает Float?
тип. Более ясно, чем приведенное ниже решение, которое просто возвращает 0
.
если вы хотите 0
значение для недопустимого Float
по какой-то причине вы можете использовать Float(Wage.text) ?? 0
что вернет 0
если это не является допустимым Float
.
Старое Решение
самый лучший путь отрегулировать это сразу кастинг:
var WageConversion = (Wage.text as NSString).floatValue
я фактически создал extension
лучше использовать такое:
extension String {
var floatValue: Float {
return (self as NSString).floatValue
}
}
теперь вы можете просто позвонить var WageConversion = Wage.text.floatValue
и позвольте расширению отрегулировать мост для вас!
это хорошая реализация, так как она может обрабатывать фактические поплавки (вход с .
), а также поможет предотвратить копирование пользователем текста в поле ввода (12p.34
, или даже 12.12.41
).
очевидно, если Apple добавляет floatValue
для Swift это будет бросать исключение, но это может быть приятно в то же время. Если они добавят его позже, то все, что вам нужно сделать, чтобы изменить свой код, это удалить расширение, и все будет работать без проблем, так как вы уже будете вызывать .floatValue
!
кроме того, переменные и константы должны начинаться с нижнего регистра (включая IBOutlets
)
потому что в некоторых частях мира, например, запятая вместо десятичной. Лучше всего создать NSNumberFormatter для преобразования строки в float.
let numberFormatter = NSNumberFormatter()
numberFormatter.numberStyle = NSNumberFormatterStyle.DecimalStyle
let number = numberFormatter.numberFromString(self.stringByTrimmingCharactersInSet(Wage.text))
я преобразую строку в Float таким образом:
let numberFormatter = NSNumberFormatter()
let number = numberFormatter.numberFromString("15.5")
let numberFloatValue = number.floatValue
println("number is \(numberFloatValue)") // prints "number is 15.5"
обновление
принятый ответ показывает более современный способ выполнения
Swift 1
вот как Пол Хегарти показал на классе CS193p Стэнфорда в 2015 году:
wageConversion = NSNumberFormatter().numberFromString(wage.text!)!.floatValue
вы даже можете создать вычисляемое свойство, чтобы не делать этого каждый раз
var wageValue: Float {
get {
return NSNumberFormatter().numberFromString(wage.text!)!.floatValue
}
set {
wage.text = "\(newValue)"
}
}
используя принятое решение, я обнаружил, что мой "1.1" (при использовании .преобразование floatValue) будет преобразовано в 1.10000002384186, что было не то, что я хотел. Однако, если я использовал .вместо doubleValue, я хотел бы получить 1.1, Что я хотел.
Так, например, вместо использования принятого решения я использовал это вместо:
var WageConversion = (Wage.text as NSString).doubleValue
в моем случае мне не нужна двойная точность, но с использованием .floatValue не давал мне надлежащего результата.
просто хотел добавить это к обсуждению, если кто-то еще столкнулся с той же проблемой.
ниже даст вам дополнительный поплавок, палка ! в конце, если вы знаете, что это поплавок, или используйте if/let.
let wageConversion = Float(wage.text)
import Foundation
"-23.67".floatValue // => -23.67
let s = "-23.67" as NSString
s.floatValue // => -23.67
вот быстрая адаптация 3 решения пола Хегарти из ответа rdprado, с некоторой проверкой на наличие дополнительных опций (возвращая 0.0, если какая-либо часть процесса терпит неудачу):
var wageFloat:Float = 0.0
if let wageText = wage.text {
if let wageNumber = NumberFormatter().number(from: wageText) {
wageFloat = wageNumber.floatValue
}
}
кстати, я взял класс CS193p Стэнфорда, используя iTunes University, когда он все еще преподавал Objective-C.
Я нашел пола Хегарти фантастическим инструктором, и я бы очень рекомендовал этот класс всем, кто начинает как разработчик iOS в Swift!!!
extension String {
func floatValue() -> Float? {
if let floatval = Float(self) {
return floatval
}
return nil
}
}
у вас есть два варианта, которые очень похожи (на подходе и результат):
// option 1:
var string_1 : String = "100"
var double_1 : Double = (string_1 as NSString).doubleValue + 99.0
// option 2:
var string_2 : NSString = "100"
// or: var string_2 = "100" as NSString
var number_2 : Double = string_2.doubleValue;
Double()
создает двойник из Int, например:
var convertedDouble = Double(someInt)
обратите внимание, что это будет работать только если ваш текст на самом деле содержит ряд. С Wage
- это текстовое поле, пользователь может ввести все, что они хотят и это вызовет ошибку времени выполнения, когда вы идете, чтобы распаковать дополнительный вернулся из toInt()
. Вы должны проверить, что преобразование удалось, прежде чем принудительно распаковывать.
if let wageInt = Wage.text?.toInt() {
//we made it in the if so the conversion succeeded.
var wageConversionDouble = Double(wageInt)
}
Edit:
если вы уверены, что текст будет целое число, вы можете сделать что-то вроде этого (обратите внимание, что text
на UITextField также необязательно)):
if let wageText = Wage.text {
var wageFloat = Double(wageText.toInt()!)
}
вот как я подошел к этому. Я не хотел "пересекать мост", так как он был удален из Xcode 6 beta 5 в любом случае, быстро и грязно:
extension String {
// converting a string to double
func toDouble() -> Double? {
// split the string into components
var comps = self.componentsSeparatedByString(".")
// we have nothing
if comps.count == 0 {
return nil
}
// if there is more than one decimal
else if comps.count > 2 {
return nil
}
else if comps[0] == "" || comps[1] == "" {
return nil
}
// grab the whole portion
var whole = 0.0
// ensure we have a number for the whole
if let w = comps[0].toInt() {
whole = Double(w)
}
else {
return nil
}
// we only got the whole
if comps.count == 1 {
return whole
}
// grab the fractional
var fractional = 0.0
// ensure we have a number for the fractional
if let f = comps[1].toInt() {
// use number of digits to get the power
var toThePower = Double(countElements(comps[1]))
// compute the fractional portion
fractional = Double(f) / pow(10.0, toThePower)
}
else {
return nil
}
// return the result
return whole + fractional
}
// converting a string to float
func toFloat() -> Float? {
if let val = self.toDouble() {
return Float(val)
}
else {
return nil
}
}
}
// test it out
var str = "78.001"
if let val = str.toFloat() {
println("Str in float: \(val)")
}
else {
println("Unable to convert Str to float")
}
// now in double
if let val = str.toDouble() {
println("Str in double: \(val)")
}
else {
println("Unable to convert Str to double")
}
для полноты это решение, использующее расширение UITextField
который также может учитывать другую локаль.
Для Swift 3+
extension UITextField {
func floatValue(locale : Locale = Locale.current) -> Float {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.locale = locale
let nsNumber = numberFormatter.number(from: text!)
return nsNumber == nil ? 0.0 : nsNumber!.floatValue
}
}
Я нашел другой способ взять входное значение UITextField и привести его к float:
var tempString:String?
var myFloat:Float?
@IBAction func ButtonWasClicked(_ sender: Any) {
tempString = myUITextField.text
myFloat = Float(tempString!)!
}
используйте этот:
// get the values from text boxes
let a:Double = firstText.text.bridgeToObjectiveC().doubleValue
let b:Double = secondText.text.bridgeToObjectiveC().doubleValue
// we checking against 0.0, because above function return 0.0 if it gets failed to convert
if (a != 0.0) && (b != 0.0) {
var ans = a + b
answerLabel.text = "Answer is \(ans)"
} else {
answerLabel.text = "Input values are not numberic"
}
простой способ:
// toInt returns optional that's why we used a:Int?
let a:Int? = firstText.text.toInt()
let b:Int? = secondText.text.toInt()
// check a and b before unwrapping using !
if a && b {
var ans = a! + b!
answerLabel.text = "Answer is \(ans)"
} else {
answerLabel.text = "Input values are not numberic"
}
вы можете использовать тот же подход для других вычислений, надеюсь, это поможет !!