NSJSONSerialization barfs writing a Dictionary parsed from JSON: "Invalid type in JSON write (_SwiftValue)"


(Jens Alfke) #1

A developer using the framework I work on just reported <https://forums.couchbase.com/t/exception-caught-in-map-block-of-view-invalid-type-in-json-write--swiftvalue/10808> an exception which is triggered by NSJSONSerialization (see backtrace below.) Basically an NSDictionary gets parsed from JSON data (in Obj-C), passed to a Swift function, which then calls another function (written in Obj-C) that serializes it back to JSON data. That last step is crashing due to some problem with bridging.

The events leading up to this are:

1. The framework (written in Obj-C) parses some JSON data using NSJSONSerialization, resulting in an NSDictionary.
2. The NSDictionary is passed as a parameter to a block; the parameter is typed as `NSDictionary*`.
3. The block is part of the application, which is written in Swift.
4. The block in turn passes that NSDictionary to a function in the framework (through a parameter is typed as `id`)
5. The framework uses NSJSONSerialization to convert that id to data.

Step 5 is triggering an assertion failure in Foundation. Apparently it failed to un-bridge a Swift value in an array back into an NSObject. (From the contents of the dictionary I know that the single-object array in question contains a string.)

Any idea what’s going on here? I’ve never seen this happen before, and this part of our framework has been around for 2 ½ years. People have successfully built Swift apps using the framework. (This app was built with Xcode 8.0; don’t know what the OS is, though.)

  Invalid type in JSON write (_SwiftValue)
  3 Foundation 0x0000000111263284 _writeJSONValue + 668
  4 Foundation 0x00000001112636d9 ___writeJSONArray_block_invoke + 132
  5 CoreFoundation 0x0000000118e1ce2a -[__NSSingleObjectArrayI enumerateObjectsWithOptions:usingBlock:] + 58
  6 Foundation 0x00000001112633df _writeJSONArray + 330
  7 Foundation 0x0000000111263204 _writeJSONValue + 540
  8 Foundation 0x0000000111262f94 -[_NSJSONWriter dataWithRootObject:options:error:] + 124
  9 Foundation 0x0000000111262e74 +[NSJSONSerialization dataWithJSONObject:options:error:] + 333
  ...

—Jens


(Dan Loewenherz) #2

I've encountered a similar bug and filed a radar a few months ago. My
report was marked as a duplicate but besides that I haven't received any
follow-up. It does appear to have been fixed in Xcode 8.1 / Swift 3.0.1.
http://www.openradar.me/28365419

Essentially, NSJSONSerialization would (does?) crash if you ask it to
encode an array/dictionary of Anys containing an optional value containing
a bridged Foundation type. The below snippet was the easiest demonstration
of the runtime exception.

    let name: String? = "Spike"
    let dogNames: [Any] = [name]

    do {
        try JSONSerialization.data(withJSONObject: dogNames, options:
.prettyPrinted)
    } catch {
        print("HI")
    }

What version of Swift is the user of your framework using?

Dan

···

On Fri, Nov 18, 2016 at 1:37 PM, Jens Alfke via swift-users < swift-users@swift.org> wrote:

A developer using the framework I work on just reported
<https://forums.couchbase.com/t/exception-caught-in-map-block-of-view-invalid-type-in-json-write--swiftvalue/10808> an
exception which is triggered by NSJSONSerialization (see backtrace below.)
Basically an NSDictionary gets parsed from JSON data (in Obj-C), passed to
a Swift function, which then calls another function (written in Obj-C) that
serializes it back to JSON data. That last step is crashing due to some
problem with bridging.

The events leading up to this are:

1. The framework (written in Obj-C) parses some JSON data using
NSJSONSerialization, resulting in an NSDictionary.
2. The NSDictionary is passed as a parameter to a block; the parameter is
typed as `NSDictionary*`.
3. The block is part of the application, which is written in Swift.
4. The block in turn passes that NSDictionary to a function in the
framework (through a parameter is typed as `id`)
5. The framework uses NSJSONSerialization to convert that id to data.

Step 5 is triggering an assertion failure in Foundation. Apparently it
failed to un-bridge a Swift value in an array back into an NSObject. (From
the contents of the dictionary I know that the single-object array in
question contains a string.)

Any idea what’s going on here? I’ve never seen this happen before, and
this part of our framework has been around for 2 ½ years. People have
successfully built Swift apps using the framework. (This app was built with
Xcode 8.0; don’t know what the OS is, though.)

Invalid type in JSON write (_SwiftValue)
3 Foundation 0x0000000111263284 _writeJSONValue
+ 668
4 Foundation 0x00000001112636d9
___writeJSONArray_block_invoke + 132
5 CoreFoundation 0x0000000118e1ce2a
-[__NSSingleObjectArrayI enumerateObjectsWithOptions:usingBlock:] + 58
6 Foundation 0x00000001112633df _writeJSONArray
+ 330
7 Foundation 0x0000000111263204 _writeJSONValue
+ 540
8 Foundation 0x0000000111262f94 -[_NSJSONWriter
dataWithRootObject:options:error:] + 124
9 Foundation 0x0000000111262e74
+[NSJSONSerialization dataWithJSONObject:options:error:] + 333
...

—Jens

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Tony Parker) #3

FYI, here is the GitHub commit that addressed this issue:

https://github.com/apple/swift/commit/1f11ef2fd29f214bd9d9a5fa85246d36c04448f0

It was also reported as SE-0140.

Basically, optional values were getting bridged to an opaque-to-Foundation “_SwiftValue” class, which means NSJSONSerialization couldn’t figure out what to do with it.

- Tony

···

On Nov 18, 2016, at 11:46 AM, Dan Loewenherz via swift-users <swift-users@swift.org> wrote:

I've encountered a similar bug and filed a radar a few months ago. My report was marked as a duplicate but besides that I haven't received any follow-up. It does appear to have been fixed in Xcode 8.1 / Swift 3.0.1. http://www.openradar.me/28365419

Essentially, NSJSONSerialization would (does?) crash if you ask it to encode an array/dictionary of Anys containing an optional value containing a bridged Foundation type. The below snippet was the easiest demonstration of the runtime exception.

    let name: String? = "Spike"
    let dogNames: [Any] = [name]

    do {
        try JSONSerialization.data(withJSONObject: dogNames, options: .prettyPrinted)
    } catch {
        print("HI")
    }

What version of Swift is the user of your framework using?

Dan

On Fri, Nov 18, 2016 at 1:37 PM, Jens Alfke via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
A developer using the framework I work on just reported <https://forums.couchbase.com/t/exception-caught-in-map-block-of-view-invalid-type-in-json-write--swiftvalue/10808> an exception which is triggered by NSJSONSerialization (see backtrace below.) Basically an NSDictionary gets parsed from JSON data (in Obj-C), passed to a Swift function, which then calls another function (written in Obj-C) that serializes it back to JSON data. That last step is crashing due to some problem with bridging.

The events leading up to this are:

1. The framework (written in Obj-C) parses some JSON data using NSJSONSerialization, resulting in an NSDictionary.
2. The NSDictionary is passed as a parameter to a block; the parameter is typed as `NSDictionary*`.
3. The block is part of the application, which is written in Swift.
4. The block in turn passes that NSDictionary to a function in the framework (through a parameter is typed as `id`)
5. The framework uses NSJSONSerialization to convert that id to data.

Step 5 is triggering an assertion failure in Foundation. Apparently it failed to un-bridge a Swift value in an array back into an NSObject. (From the contents of the dictionary I know that the single-object array in question contains a string.)

Any idea what’s going on here? I’ve never seen this happen before, and this part of our framework has been around for 2 ½ years. People have successfully built Swift apps using the framework. (This app was built with Xcode 8.0; don’t know what the OS is, though.)

  Invalid type in JSON write (_SwiftValue)
  3 Foundation 0x0000000111263284 _writeJSONValue + 668
  4 Foundation 0x00000001112636d9 ___writeJSONArray_block_invoke + 132
  5 CoreFoundation 0x0000000118e1ce2a -[__NSSingleObjectArrayI enumerateObjectsWithOptions:usingBlock:] + 58
  6 Foundation 0x00000001112633df _writeJSONArray + 330
  7 Foundation 0x0000000111263204 _writeJSONValue + 540
  8 Foundation 0x0000000111262f94 -[_NSJSONWriter dataWithRootObject:options:error:] + 124
  9 Foundation 0x0000000111262e74 +[NSJSONSerialization dataWithJSONObject:options:error:] + 333
  ...

—Jens

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users