Open flockoffiles opened 2 months ago
Do you have a workaround?
The only workaround I know is going back to Xcode 16 beta 4 (and praying that this issue gets fixed soon).
Experiencing the same issue.
ok. There seems to be a work-around. It's quite verbose, but it works:
let decimalNumber = NSDecimalNumber(decimal: tmpDecimal)
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.locale = locale
let formattedString = numberFormatter.string(from: decimalNumber) ?? "\(tmpDecimal)"
EDIT: Please see @robertmryan's comment below before choosing to use the approach I suggested here. Decimal.FormatStyle
behaves differently from NumberFormatter
in some scenarios.
It seems this is a known issue on Xcode 16.
According to the release notes, the suggested workaround is to use Decimal.FormatStyle. If you're supporting iOS 15.0 and above, you can do something like this too:
let decimalNumber: Decimal = 12345.67
let formatStyle = Decimal.FormatStyle(locale: locale)
let formattedNumber = decimalNumber.formatted(formatStyle)
let formattedNumberStr = String(formattedNumber)
The main advantage of this approach is that you don't have to deal with optionals.
I agree that for now we can just avoid using NSDecimalString
, but, FWIW, the error message tells us what the problem is: The Swift interface indicates that the result is not optional, as indicated in the docs, but clearly elsewhere behind the scenes, it is being inferred as optional.
@alvesmarcel
It seems this is a known issue on Xcode 16.
According to the release notes, the suggested workaround is to use
Decimal.FormatStyle
. If you're supporting iOS 15.0 and above, you can do something like this too:let decimalNumber: Decimal = 12345.67 let formatStyle = Decimal.FormatStyle(locale: locale) let formattedNumber = decimalNumber.formatted(formatStyle) let formattedNumberStr = String(formattedNumber)
The main advantage of this approach is that you don't have to deal with optionals.
I would be cautious with this: If the locale is your current
locale, this will use the default numeric format for that locale, but it will ignore whatever custom number formatting you may have changed in settings. NumberFormatter
will honor the device settings, but Decimal.FormatStyle
will not. If you’re trying to generate some invariant style (a la en_US_POSIX
), this doesn’t matter. But if trying to localize in a manner to honor the device settings, this is problematic.
@robertmryan that solution has merged so you might want to copy your feedback to that PR or share an alternative
@aehlke
Are you talking about [swift5] Fix Xcode 16 compilation crash with Extensions.swift generation #19564? All those changes were using Locale(identifier: "en_US")
. (Personally, I would have advised Locale(identifier: "en_US_POSIX")
, but that distinction is subtle and beyond the scope of this conversation.) Using a fixed locale is fine. The limitations of formatted(_:)
with Decimal.FormatStyle
with locale
of .current
(or, worse, formatted()
) only manifest themselves in those cases where one might reasonably assume that it would honor not only the device locale (which it will), but also any override settings of the “number format” in “Settings” (which it doesn't).
Or is there some other PR that you are referencing?
Got the same issue on 16.0 RC
I have some SPM created by OpenAPI for our app, and the SDKs created there uses NSDecimalString
.
So I can't manually change these
Can I go back to a 16.0 beta where this is not an issue?
https://github.com/OpenAPITools/openapi-generator/issues/19459
@alvesmarcel
It seems this is a known issue on Xcode 16. According to the release notes, the suggested workaround is to use
Decimal.FormatStyle
. If you're supporting iOS 15.0 and above, you can do something like this too:let decimalNumber: Decimal = 12345.67 let formatStyle = Decimal.FormatStyle(locale: locale) let formattedNumber = decimalNumber.formatted(formatStyle) let formattedNumberStr = String(formattedNumber)
The main advantage of this approach is that you don't have to deal with optionals.
I would be cautious with this: If the locale is your
current
locale, this will use the default numeric format for that locale, but it will ignore whatever custom number formatting you may have changed in settings.NumberFormatter
will honor the device settings, butDecimal.FormatStyle
will not. If you’re trying to generate some invariant style (a laen_US_POSIX
), this doesn’t matter. But if trying to localize in a manner to honor the device settings, this is problematic.
Thanks for pointing that out, @robertmryan! I wasn’t aware of that important difference in behavior. Do you know if there’s a way for Decimal.FormatStyle
to behave like NumberFormatter
? I’m asking because the documentation suggests Decimal.FormatStyle
as an alternative to NumberFormatter
, so I’m wondering if I’m missing something in my implementation.
Thanks for pointing that out, @robertmryan! I wasn’t aware of that important difference in behavior. Do you know if there’s a way for
Decimal.FormatStyle
to behave likeNumberFormatter
? I’m asking because the documentation suggestsDecimal.FormatStyle
as an alternative toNumberFormatter
, so I’m wondering if I’m missing something in my implementation.
@alvesmarcel – No, I don’t. So, when trying to format for the end-user’s preferred format, I stick with NumberFormatter
. I only use this formatted
function when dealing with fixed locales, like en_US_POSIX
.
To make using NumberFormatter
a little more natural with string interpolation, I personally extend default string interpolation behavior to support NumberFormatter
:
extension String.StringInterpolation {
mutating func appendInterpolation<T: Numeric>(_ value: T, using formatter: NumberFormatter) {
if let formattedValue = formatter.string(for: value) {
appendLiteral(formattedValue)
}
}
}
Then I can use NumberFormatter
in my string interpolation:
let string = "\(value, using: formatter)")
FWIW, with floating points, you can use the specifier
alternative and that seems to localize properly:
let string = "\(value, specifier: "%.2f")"
But that does not work with Decimal
, hence my NumberFormatter
approach outlined above.
Description
The following code that calls NSDecimalString crashes the compiler with the message:
SILFunction type mismatch for 'NSDecimalString': '$@convention(c) (UnsafePointer, Optional) -> @autoreleased Optional' != '$@convention(c) (UnsafePointer, Optional) -> @autoreleased NSString'
Reproduction
Stack dump
Expected behavior
I expect it compile without a crash.
Environment
swift-driver version: 1.113 Apple Swift version 6.0 (swiftlang-6.0.0.7.6 clang-1600.0.24.1) Target: arm64-apple-macosx14.0
Additional information
DecimalStringBug.zip