Double(text) to convert a string written in Swift’s numeric format. It returns an optional, so handle nil for empty or invalid input; use NumberFormatter when the text follows a user’s locale, such as a comma decimal separator.Why this happens
Swift does not convert arbitrary text to a Double automatically. The modern conversion API is the failable initializer Double(_:): it produces a Double when the string contains a number in a format Swift can parse, and nil otherwise. Its return type is Double?, not a guaranteed number.
That optional result is important for user input. A text field can be empty or contain letters, a decimal separator from another locale, or other unexpected characters. Older Objective-C-style conversion through NSString.doubleValue can make invalid text look like a valid zero. For example, it does not let you reliably distinguish a failed conversion from the input "0".
There are two common cases: a string in Swift’s standard numeric format, such as "3.14", and formatted text intended for people in a particular locale, such as "3,14". Use Double for the first case and a locale-aware NumberFormatter for the second.
How to fix it
1. Convert a standard numeric string with Double
Use the Double initializer directly:
let value = Double("3.14") // Optional(3.14)
let invalid = Double("alphabet") // nil
Because the result is optional, unwrap it before using it. For text from a UIKit text field, avoid force-unwrapping textField.text—that property is optional too:
if let text = textField.text,
let value = Double(text) {
print("The entered value is \(value)")
} else {
print("Enter a valid number")
}
If you want to allow leading or trailing whitespace, trim it before conversion. This also makes an input containing only whitespace fail as an empty value rather than being treated as a number:
import Foundation
let rawText = textField.text ?? ""
let text = rawText.trimmingCharacters(in: .whitespacesAndNewlines)
if let value = Double(text) {
print("The entered value is \(value)")
} else {
print("Enter a valid number")
}
Use guard when the rest of a function should run only after the conversion succeeds:
func calculateBMI(weightText: String, heightText: String) {
guard let weight = Double(weightText),
let height = Double(heightText),
weight > 0,
height > 0 else {
print("Enter valid positive numbers for weight and height")
return
}
let bmi = weight / (height * height)
print("BMI: \(bmi)")
}
This example expects values in units that make the BMI formula valid—for example, weight in kilograms and height in metres. The important conversion detail is that each parse can fail, so the function checks both values before calculating.
2. Use NumberFormatter for localized decimal input
Double("3.14") uses a period in the decimal representation. If your app accepts text according to the user’s locale, a decimal comma such as "3,14" may not parse with Double. Configure NumberFormatter with a locale and decimal style instead:
import Foundation
func parseLocalizedDecimal(_ text: String) -> Double? {
let formatter = NumberFormatter()
formatter.locale = .current
formatter.numberStyle = .decimal
return formatter.number(from: text)?.doubleValue
}
if let value = parseLocalizedDecimal("3,14") {
print(value)
} else {
print("Enter a valid number")
}
The example uses the device’s current locale; whether "3,14" is accepted depends on that locale’s number conventions. If your app requires a particular input format regardless of device settings, set an explicit locale instead:
formatter.locale = Locale(identifier: "fr_FR")
Choose a locale that matches the format you expect users to enter. Do not replace commas with periods blindly: commas can be decimal separators in some locales and grouping separators in others. A formatter is also preferable when parsing currency-style text. Configure its numberStyle as .currency and its locale to match the expected currency format. For calculations, keep the parsed numeric value; do not use a formatted display string as the value to calculate with.
3. Keep the parse failure visible in the interface
A failed conversion should lead to a useful validation state, not a forced unwrap or a silent zero. For example, separate parsing from the action that uses the value:
func submitAmount(_ input: String) {
guard let amount = Double(input) else {
print("Please enter an amount such as 12.50")
return
}
save(amount)
}
func save(_ amount: Double) {
// Use the parsed value here.
}
If the input is localized, call your NumberFormatter-based parser in the same place instead. Choose one parsing rule for the field and use it consistently; otherwise the displayed format and accepted input can disagree.
For a fixed, trusted string that you know is valid, you can force-unwrap the optional, but this is generally unsuitable for user input. A malformed string would cause a runtime crash. Prefer if let or guard let so failure is handled deliberately.
How to prevent it
- Treat
Double(text)as a fallible operation and handle itsnilresult. - Do not use
NSString.doubleValuewhen invalid input must be distinguished from zero. - Do not force-unwrap text-field content or the result of a conversion.
- Decide whether input follows Swift’s period-based numeric format or the user’s locale.
- Validate constraints such as positive values after parsing; successful conversion alone does not make a value appropriate for your calculation.
- Keep number formatting for display separate from numeric values used in calculations.
FAQ
Why does Double("3,14") return nil?
Double expects a numeric string in Swift’s standard representation, which uses a period for the decimal separator. For localized input, use NumberFormatter configured for the expected locale.
Does Double(String) return a Double or an optional?
It returns Double?. A valid numeric string produces a value; text that cannot be parsed produces nil, which you must unwrap before using it.
Should I use NSString.doubleValue instead?
Usually not for user input. It can return zero for text that is not a valid number, making invalid input hard to distinguish from an actual zero. Use Double(_:) or a locale-configured NumberFormatter instead.
Parts of this guide are adapted from content licensed under CC BY-SA 4.0; this article is shared under the same license.
