Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write a prettyPrinted JSON object with sorted keys in Swift

We often want to use JSON for human readability. As such, it is common to ask to sort the JSON keys alphabetically (or alphanumerically) in Go, in .NET, in Python, in Java, ...

But how to output a JSON with JSON keys sorted alphabetically in Swift?

PrettyPrinted output is easy:

JSONSerialization.writeJSONObject(jsonObject, to: outputStream, options: [.prettyPrinted], error: nil)

Yet the keys are not alphabetically sorted for human readability. They are likely in the order given by NSDictionary.keyEnumerator(). But sadly, we can't subclass Dictionary, NSDictionary or CFDictionary in Swift, so we can't override the behavior of keys order.

[edit: actually, we can subclass NSDictionary, see one of my answers below]

like image 441
Cœur Avatar asked Sep 04 '17 07:09

Cœur


1 Answers

Solution for iOS 7+, macOS 10.9+ (OS X Mavericks and up).

A solution is to subclass NSDictionary in Objective-C, then use the subclass from a framework (for Application) or static library (for Command Line Tool).

For this demonstration, I will use nicklockwood/OrderedDictionary (700+ lines of code) instead of doing it from scratch, but there may be untested alternatives like quinntaylor/CHOrderedDictionary or rhodgkins/RDHOrderedDictionary. To integrate it as a Framework, add this dependency in your PodFile:

pod 'OrderedDictionary', '~> 1.4'

Then we will order the keys of our object:

import OrderedDictionary

let orderedJson = MutableOrderedDictionary()
jsonObject.sorted { $0.0.compare($1.0, options: [.forcedOrdering, .caseInsensitive]) == .orderedAscending }
          .forEach { orderedJson.setObject($0.value, forKey: $0.key) }

(note: setObject(_,forKey:) is specific to MutableOrderedDictionary)
And finally we can write it prettyPrinted:

_ = JSONSerialization.writeJSONObject(orderedJson, to: outputJSON, options: [.prettyPrinted], error: nil)

But be careful: you need to subclass and sort all subdictionaries of your JSON object.

like image 153
Cœur Avatar answered Nov 10 '22 10:11

Cœur