简体   繁体   中英

Why does NumberFormatter's string(from:) return an optional?

Documentation link

Why does the NumberFormatter function func string(from number: NSNumber) -> String? return a String? rather than a String ? Are there particular inputs or states for a NumberFormatter where this function could return nil? Sometimes I hear these less-than-ideal return types are from Objective-C holdover files, is this one of those cases?

Just for fun: Here is a (constructed, not real-world) example where string(from:) actually returns nil :

let num = NSNumber(bytes: UnsafeRawPointer(bitPattern: 1)!, objCType: "v")
print(num) // <>

let fmt = NumberFormatter()
fmt.numberStyle = .decimal
let str = fmt.string(from: num)

print(str as Any) // nil

The reason is that this num does not represent a number: It is created using the NSValue (from which its inherits) initializer init(bytes:objCType:) with a value representing void . ("v" is the type encoding for void , the pointer value is irrelevant.)

There's an ancient (2002) response on the Apple mailing list which might partially answer your question:

The strange behavior isn't NSNumber -- NSNumber -stringValue seems to be returning results one would expect. It's NSNumberFormatter which is returning unusual results.

The abstract problem here is that NSNumberFormatter was originally written to handle money amounts for EOF, so it doesn't deal with unusual numbers well (or general purpose string formatting for that matter).

The more concrete problem is that when you ask an NSNumberFormatter for -stringForObjectValue:, if the object is not an NSDecimalNumber, it converts it to an NSDecimalNumber using [NSDecimalNumber decimalNumberWithString:[objectValue stringValue]] which is not going to handle unusual values well, in addition to potentially other issues. A further issue, though I don't know this is the case, is that I don't think there is an NSDecimal (the struct) representation of positive and negative infinity, as there is for NaN.

I don't actually understand that response enough to say that it's why an optional is returned, but I suspect it's related.

There's example code in the original question, but none of it returns a nil , it always gives a string.

I think it's fait to say that, if you try to format a common type (like Double) to String using a NumberFormatter, there is no way it would return nil .

In my opinion, this is one of the few cases where force-unwrapped optionals make perfect sense.

func formatToDecimalNumber(_ value: Double) -> String {
    let formatter = NumberFormatter()
    formatter.numberStyle = .decimal
    formatter.minimumFractionDigits = 0
    formatter.maximumFractionDigits = 2
    formatter.locale = Locale.current
    return formatter.string(from: NSNumber(value: value))!
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM