Skip to content

Commit 27d76fc

Browse files
committed
JSONSerialization: add WritingOptions.sortedKeys
1 parent 6d107c1 commit 27d76fc

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

Foundation/NSJSONSerialization.swift

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ extension JSONSerialization {
3131
public init(rawValue: UInt) { self.rawValue = rawValue }
3232

3333
public static let prettyPrinted = WritingOptions(rawValue: 1 << 0)
34+
public static let sortedKeys = WritingOptions(rawValue: 1 << 1)
3435
}
3536
}
3637

@@ -116,6 +117,7 @@ open class JSONSerialization : NSObject {
116117

117118
var writer = JSONWriter(
118119
pretty: opt.contains(.prettyPrinted),
120+
sortedKeys: opt.contains(.sortedKeys),
119121
writer: { (str: String?) in
120122
if let str = str {
121123
jsonStr.append(str)
@@ -289,6 +291,7 @@ private struct JSONWriter {
289291
private let maxIntLength = String(describing: Int.max).characters.count
290292
var indent = 0
291293
let pretty: Bool
294+
let sortedKeys: Bool
292295
let writer: (String?) -> Void
293296

294297
private lazy var _numberformatter: CFNumberFormatter = {
@@ -299,8 +302,9 @@ private struct JSONWriter {
299302
return formatter
300303
}()
301304

302-
init(pretty: Bool = false, writer: @escaping (String?) -> Void) {
305+
init(pretty: Bool = false, sortedKeys: Bool = false, writer: @escaping (String?) -> Void) {
303306
self.pretty = pretty
307+
self.sortedKeys = sortedKeys
304308
self.writer = writer
305309
}
306310

@@ -501,8 +505,19 @@ private struct JSONWriter {
501505
}
502506

503507
var first = true
508+
509+
var keys = Array(dict.keys)
510+
if sortedKeys {
511+
try keys.sort(by: { a, b in
512+
guard let a = a as? String,
513+
let b = b as? String else {
514+
throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.propertyListReadCorrupt.rawValue, userInfo: ["NSDebugDescription" : "NSDictionary key must be NSString"])
515+
}
516+
return a < b
517+
})
518+
}
504519

505-
for (key, value) in dict {
520+
for key in keys {
506521
if first {
507522
first = false
508523
} else if pretty {
@@ -518,7 +533,7 @@ private struct JSONWriter {
518533
throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.propertyListReadCorrupt.rawValue, userInfo: ["NSDebugDescription" : "NSDictionary key must be NSString"])
519534
}
520535
pretty ? writer(": ") : writer(":")
521-
try serializeJSON(value)
536+
try serializeJSON(dict[key]!)
522537
}
523538
if pretty {
524539
writer("\n")

TestFoundation/TestNSJSONSerialization.swift

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -945,11 +945,12 @@ extension TestNSJSONSerialization {
945945
("test_booleanJSONObject", test_booleanJSONObject),
946946
("test_serialize_dictionaryWithDecimal", test_serialize_dictionaryWithDecimal),
947947
("test_serializeDecimalNumberJSONObject", test_serializeDecimalNumberJSONObject),
948+
("test_serializeSortedKeys", test_serializeSortedKeys),
948949
]
949950
}
950951

951-
func trySerialize(_ obj: Any) throws -> String {
952-
let data = try JSONSerialization.data(withJSONObject: obj, options: [])
952+
func trySerialize(_ obj: Any, options: JSONSerialization.WritingOptions = []) throws -> String {
953+
let data = try JSONSerialization.data(withJSONObject: obj, options: options)
953954
guard let string = String(data: data, encoding: .utf8) else {
954955
XCTFail("Unable to create string")
955956
return ""
@@ -1334,6 +1335,19 @@ extension TestNSJSONSerialization {
13341335
} catch {
13351336
XCTFail("Failed during serialization")
13361337
}
1338+
}
1339+
1340+
func test_serializeSortedKeys() {
1341+
var dict: [String: Any]
1342+
1343+
dict = ["z": 1, "y": 1, "x": 1, "w": 1, "v": 1, "u": 1, "t": 1, "s": 1, "r": 1, "q": 1, ]
1344+
XCTAssertEqual(try trySerialize(dict, options: .sortedKeys), "{\"q\":1,\"r\":1,\"s\":1,\"t\":1,\"u\":1,\"v\":1,\"w\":1,\"x\":1,\"y\":1,\"z\":1}")
1345+
1346+
dict = ["aaaa": 1, "aaa": 1, "aa": 1, "a": 1]
1347+
XCTAssertEqual(try trySerialize(dict, options: .sortedKeys), "{\"a\":1,\"aa\":1,\"aaa\":1,\"aaaa\":1}")
1348+
1349+
dict = ["c": ["c":1,"b":1,"a":1],"b":["c":1,"b":1,"a":1],"a":["c":1,"b":1,"a":1]]
1350+
XCTAssertEqual(try trySerialize(dict, options: .sortedKeys), "{\"a\":{\"a\":1,\"b\":1,\"c\":1},\"b\":{\"a\":1,\"b\":1,\"c\":1},\"c\":{\"a\":1,\"b\":1,\"c\":1}}")
13371351
}
13381352

13391353
fileprivate func createTestFile(_ path: String,_contents: Data) -> String? {

0 commit comments

Comments
 (0)