Skip to content

Commit 89deb3f

Browse files
committed
decoupling formatting logic and lazy loading formatter
1. moved format logic out of NSNumber and in to NSJSonSerialization 2. lazy load the formatter to be instantiated if needed 3. create a single format string to work with all formats since we are lazy loading a single formatter
1 parent 8bf5675 commit 89deb3f

File tree

3 files changed

+28
-17
lines changed

3 files changed

+28
-17
lines changed

Foundation/NSJSONSerialization.swift

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
88
//
99

10+
import CoreFoundation
11+
1012
#if os(OSX) || os(iOS)
1113
import Darwin
1214
#elseif os(Linux)
@@ -240,6 +242,14 @@ private struct JSONWriter {
240242
let pretty: Bool
241243
let writer: (String?) -> Void
242244

245+
private lazy var _numberformatter: CFNumberFormatter = {
246+
let formatter: CFNumberFormatter
247+
formatter = CFNumberFormatterCreate(nil, CFLocaleCopyCurrent(), kCFNumberFormatterNoStyle)
248+
CFNumberFormatterSetProperty(formatter, kCFNumberFormatterMaxFractionDigits, 15._bridgeToObject())
249+
CFNumberFormatterSetFormat(formatter, "0.###############"._cfObject)
250+
return formatter
251+
}()
252+
243253
init(pretty: Bool = false, writer: @escaping (String?) -> Void) {
244254
self.pretty = pretty
245255
self.writer = writer
@@ -298,15 +308,15 @@ private struct JSONWriter {
298308
writer("\"")
299309
}
300310

301-
func serializeNumber(_ num: NSNumber) throws {
311+
mutating func serializeNumber(_ num: NSNumber) throws {
302312
if num.doubleValue.isInfinite || num.doubleValue.isNaN {
303313
throw NSError(domain: NSCocoaErrorDomain, code: NSCocoaError.PropertyListReadCorruptError.rawValue, userInfo: ["NSDebugDescription" : "Number cannot be infinity or NaN"])
304314
}
305315

306316
// Cannot detect type information (e.g. bool) as there is no objCType property on NSNumber in Swift
307317
// So, just print the number
308318

309-
writer(num.serializationString)
319+
writer(_serializationString(for: num))
310320
}
311321

312322
mutating func serializeArray(_ array: NSArray) throws {
@@ -389,6 +399,11 @@ private struct JSONWriter {
389399
writer(" ")
390400
}
391401
}
402+
403+
//[SR-2151] https://bugs.swift.org/browse/SR-2151
404+
private mutating func _serializationString(for number: NSNumber) -> String {
405+
return CFNumberFormatterCreateStringWithNumber(nil, _numberformatter, number._cfObject)._swiftObject
406+
}
392407
}
393408

394409
//MARK: - JSONDeserializer

Foundation/NSNumber.swift

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ open class NSNumber : NSValue {
139139
// This layout MUST be the same as CFNumber so that they are bridgeable
140140
private var _base = _CFInfo(typeID: CFNumberGetTypeID())
141141
private var _pad: UInt64 = 0
142+
142143
internal var _cfObject: CFType {
143144
return unsafeBitCast(self, to: CFType.self)
144145
}
@@ -450,23 +451,8 @@ open class NSNumber : NSValue {
450451
open override var description: String {
451452
return description(withLocale: nil)
452453
}
453-
454-
//[SR-2151] https://bugs.swift.org/browse/SR-2151
455-
internal var serializationString: String {
456-
let formatter: CFNumberFormatter
457-
formatter = CFNumberFormatterCreate(nil, CFLocaleCopyCurrent(), kCFNumberFormatterNoStyle)
458-
CFNumberFormatterSetProperty(formatter, kCFNumberFormatterMaxFractionDigits, 15._bridgeToObject())
459-
switch CFNumberGetType(_cfObject as CFNumber){
460-
case .floatType, .float32Type, .float64Type, .cgFloatType, .doubleType:
461-
CFNumberFormatterSetFormat(formatter, "0.###############"._cfObject);
462-
default:break
463-
}
464-
return CFNumberFormatterCreateStringWithNumber(nil, formatter, self._cfObject)._swiftObject
465-
}
466454
}
467455

468-
469-
470456
extension CFNumber : _NSBridgable {
471457
typealias NSType = NSNumber
472458
internal var _nsObject: NSType { return unsafeBitCast(self, to: NSType.self) }

TestFoundation/TestNSJSONSerialization.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,9 +691,19 @@ extension TestNSJSONSerialization {
691691
XCTAssertEqual(str!, "{\"\(param.0)\":\(param.0._bridgeToObject().intValue)}", "expect that serialized value should not contain trailing zero or decimal as they are whole numbers ")
692692
}
693693
}
694+
695+
func excecute_testWholeNumbersWithIntInput() {
696+
for i in -10..<10 {
697+
let iStr = "\(i)"
698+
let testDict = [iStr : i as AnyObject] as [String : AnyObject]
699+
let str = try? trySerialize(testDict.bridge())
700+
XCTAssertEqual(str!, "{\"\(iStr)\":\(i)}", "expect that serialized value should not contain trailing zero or decimal as they are whole numbers ")
701+
}
702+
}
694703
excecute_testSetLessThanOne()
695704
excecute_testSetGraterThanOne()
696705
excecute_testWholeNumbersWithDoubleAsInput()
706+
excecute_testWholeNumbersWithIntInput()
697707
}
698708

699709
func test_serialize_null() {

0 commit comments

Comments
 (0)