JSONKit v1.4 Release Notes

Release Date: 2011-03-23 // over 10 years ago

Previous changes from v1.3

  • 🆕 New Features

    • Added the JK_ENABLE_CF_TRANSFER_OWNERSHIP_CALLBACKS pre-processor define flag.

      This is typically enabled by adding -DJK_ENABLE_CF_TRANSFER_OWNERSHIP_CALLBACKS to the compilers command line arguments or in Xcode.app by adding JK_ENABLE_CF_TRANSFER_OWNERSHIP_CALLBACKS to a projects / targets Pre-Processor Macros settings.

      The JK_ENABLE_CF_TRANSFER_OWNERSHIP_CALLBACKS option enables the use of custom Core Foundation collection call backs which omit the [CFRetain][CFRetain] calls. This results in saving several [CFRetain][CFRetain] and [CFRelease][CFRelease] calls typically needed for every single object from the parsed JSON. While the author has used this technique for years without any issues, an unexpected interaction with the Foundation [-mutableCopy][-mutableCopy] method and Core Foundation Toll-Free Bridging resulting in a condition in which the objects contained in the collection to be over released. This problem does not occur with the use of [-copy][-copy] due to the fact that the objects created by JSONKit are immutable, and therefore [-copy][-copy] does not require creating a completely new object and copying the contents, instead [-copy][-copy] simply returns a [-retain][-retain]'d version of the immutable object which is significantly faster along with the obvious reduction in memory usage.

      Prior to version 1.3, JSONKit always used custom "Transfer of Ownership Collection Callbacks", and thus JK_ENABLE_CF_TRANSFER_OWNERSHIP_CALLBACKS was effectively implicitly defined.

      Beginning with version 1.3, the default behavior of JSONKit is to use the standard Core Foundation collection callbacks ([kCFTypeArrayCallBacks][kCFTypeArrayCallBacks], [kCFTypeDictionaryKeyCallBacks][kCFTypeDictionaryKeyCallBacks], and [kCFTypeDictionaryValueCallBacks][kCFTypeDictionaryValueCallBacks]). The intention is to follow "the principle of least surprise", and the author believes the use of the standard Core Foundation collection callbacks as the default behavior for JSONKit results in the least surprise.

      NOTE: JK_ENABLE_CF_TRANSFER_OWNERSHIP_CALLBACKS is only applicable to (CF|NS) Dictionary and Array class objects.

      For the vast majority of users, the author believes JSONKits custom "Transfer of Ownership Collection Callbacks" will not cause any problems. As previously stated, the author has used this technique in performance critical code for years and has never had a problem. Until a user reported a problem with [-mutableCopy][-mutableCopy], the author was unaware that the use of the custom callbacks could even cause a problem. This is probably due to the fact that the vast majority of time the typical usage pattern tends to be "iterate the contents of the collection" and very rarely mutate the returned collection directly (although this last part is likely to vary significantly from programmer to programmer). The author tends to avoid the use of [-mutableCopy][-mutableCopy] as it results in a significant performance and memory consumption penalty. The reason for this is in "typical" Cocoa coding patterns, using [-mutableCopy][-mutableCopy] will instantiate an identical, albeit mutable, version of the original object. This requires both memory for the new object and time to iterate the contents of the original object and add them to the new object. Furthermore, under "typical" Cocoa coding patterns, the original collection object continues to consume memory until the autorelease pool is released. However, clearly there are cases where the use of [-mutableCopy][-mutableCopy] makes sense or may be used by an external library which is out of your direct control.

      The use of the standard Core Foundation collection callbacks results in a 9% to 23% reduction in parsing performance, with an "eye-balled average" of around 13% according to some benchmarking done by the author using Real World™ JSON (i.e., actual JSON from various web services, such as Twitter, etc) using gcc-4.2 -arch x86_64 -O3 -DNS_BLOCK_ASSERTIONS with the only change being the addition of -DJK_ENABLE_CF_TRANSFER_OWNERSHIP_CALLBACKS.

      JK_ENABLE_CF_TRANSFER_OWNERSHIP_CALLBACKS is only applicable to parsing / deserializing (i.e. converting from) of JSON. Serializing (i.e., converting to JSON) is completely unaffected by this change.

    🐛 Bug Fixes

    Other Changes

    • Added JK_EXPECTED optimization hints around several conditionals.
    • When serializing objects, JSONKit first starts with a small, on stack buffer. If the encoded JSON exceeds the size of the stack buffer, JSONKit switches to a heap allocated buffer. If JSONKit switched to a heap allocated buffer, [CFDataCreateWithBytesNoCopy][CFDataCreateWithBytesNoCopy] is used to create the [NSData][NSData] object, which in most cases causes the heap allocated buffer to "transfer" to the [NSData][NSData] object which is substantially faster than allocating a new buffer and copying the bytes.
    • 👀 Added a pre-processor check in JSONKit.m to see if Objective-C Garbage Collection is enabled and issue a #error notice that JSONKit does not support Objective-C Garbage Collection.
    • ⚡️ Various other minor or trivial modifications, such as updating README.md.

    Other Issues

    • When using the clang static analyzer (the version used at the time of this writing was Apple clang version 1.5 (tags/Apple/clang-60)), the static analyzer reports a number of problems with JSONKit.m.

      The author has investigated these issues and determined that the problems reported by the current version of the static analyzer are "false positives". Not only that, the reported problems are not only "false positives", they are very clearly and obviously wrong. Therefore, the author has made the decision that no action will be taken on these non-problems, which includes not modifying the code for the sole purpose of silencing the static analyzer. The justification for this is "the dog wags the tail, not the other way around."