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

前端 未结 3 1144
后悔当初
后悔当初 2021-01-04 05:43

Documentation link

Why does the NumberFormatter function func string(from number: NSNumber) -> String? return a String? rat

相关标签:
3条回答
  • 2021-01-04 05:59

    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.

    0 讨论(0)
  • 2021-01-04 06:03

    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))!
    }
    
    0 讨论(0)
  • 2021-01-04 06:09

    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.)

    0 讨论(0)
提交回复
热议问题