A much faster version of JSONDecoder
These benchmarks were done on a Macbook Pro. The results are very similar on the iPhone (ZippyJSON is 3x+ faster for all 3 files on both platforms).
ZippyJSONDecoder wherever you want to use it. So instead of
let decoder = JSONDecoder(), do
let decoder = ZippyJSONDecoder(), and everything will just work. This is because
ZippyJSONDecoder has the exact same API as
JSONDecoder (i.e. it's drop-in). Also, don't forget to add
import ZippyJSON in files where you use it.
Why is it so much faster?
- Apple's version first converts the JSON into an
NSJSONSerializationand then afterwards makes things Swifty. The creation of that intermediate dictionary is expensive.
- ZippyJSON is built largely in C++ (but still with a Swift interface wrapped around it). For the initial parsing (you might call it tokenizing), it uses simdjson, a very fast library that makes good use of vectorization. Apple, on the other hand, uses entirely Swift (aside from the use of
NSJSONSerialization) which is generally slower.
- There are many specific optimizations in there as well. For example, date parsing for ISO-8601 dates is 10x faster due to using JJLISO8601DateFormatter instead of Apple's date formatter.
So, it's largely due to Apple trying to be elegant and operate at a higher level.
When should you use this library?
At first, default to using
JSONDecoder. It's very battle-tested, and for plenty of use cases is just fine. Then, once you start looking for new things to optimize, take a look at how long your JSON parsing is taking. After all, JSON parsing can be a bottleneck for getting data to the user. As a rule of thumb, divide its current time taken by 4 to approximate the time taken with ZippyJSON. If that difference is significant to you (and even milliseconds can impact a user experience!), then consider using ZippyJSON.
There are still many places in the code that are ripe for optimization. Feel free to submit a ticket if you have a specific case where you need more performant JSON parsing, and where ZippyJSON is not already 4x faster than Apple's. JSONEncoder and NSJSONSerialization are also promising for optimzation, please chime in if you need one of these improved.
ZippyJSON is available through CocoaPods (SPM support is in the works). To install it, simply add the following line to your Podfile:
You can also make it
pod 'ZippyJSON', :inhibit_warnings => true if you want to suppress all warnings.
SwiftPM (iOS only)
Add the package in the SwiftPM packages area with repository URL https://github.com/michaeleisel/ZippyJSON
Michael Eisel, email@example.com
You may find interesting
- Improved performance when
codingPathis being computed a lot (e.g., because the decoding has a lot of errors being thrown and caught)
- More accurate results for
codingPath- there are no longer any known issues with it, and in some cases it's more accurate than Apple
- Fixed theoretical use-after-free issue in a situation where a
UnkeyedDecodingContainerwere to somehow live on after the parent decoder has been deallocated
- ZippyJSON now uses the fastest string-to-double parser in existence (co-authored by @lemire and I, and included as part of simdjson 0.3.1)
- simdjson, which does a lot of behind-the-scenes processing for ZippyJSON, is now upgraded to version 0.3.1. As a result of the new APIs, the ZippyJSON code is now substantially simpler
- Fixed bug that occurred when having a new
UnkeyedDecodingContainervariable point to an existing one (https://github.com/michaeleisel/ZippyJSON/issues/24)
- Other minor bug fixes and improvements
- Fixed double-free error in rare conditions (when Swift throws an exception upon trying to make a keyed decoding container with a non-dictionary JSON entity, which is then caught within the decoding init method, and then later tries to construct another object of that type)
A number of stability improvements and performance upgrades:
- Many more unit tests, and 96%+ test coverage 🎉
- Fixed bug around custom implementations of
init(with: Decoder)that use an unkeyed container or a super decoder
- Fixed bug around custom implementations of
init(with: Decoder)that use
decodeNil, where it would skip over a non-nil array item if there was one
- Fixed issue when decoding a
- Reduced memory consumption during decoding
- Added conformance to
- Better performance, due to a number of changes: all test JSON files have been benchmarked as being 4-6x faster on both platforms (previously, it was only 3x+)
Do not use this version, as it has issues with SwiftPM
- Added SwiftPM support 🎉 (iOS only, due to issues with SwiftPM)
- Fixed bug where non-ASCII chars in a string in a JSON array would cause a performance regression
- Reworked the C++ layer to use way fewer thread-locals, making the ZippyJSON reentrant and using less global locking
- Fixed memory leak with floating-point error strings
- Provide better error message when the JSON data given is 0 bytes in length