Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What do JSONSerialization options do and how do they change jsonResult?

I am using JSONSerialization quite often in my project. Here is an example of my JSONSerialization code:

let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any] 

Note: Options are missing for purpose and I normally have them in my project.

My problem is that I am not pretty sure what do these options: [] do?

What I have found about options:

NSJSONReadingMutableContainers:

Specifies that arrays and dictionaries are created as mutable objects.

NSJSONReadingMutableLeaves:

Specifies that leaf strings in the JSON object graph are created as instances of NSMutableString.

NSJSONReadingAllowFragments:

Specifies that the parser should allow top-level objects that are not an instance of NSArray or NSDictionary.

Note2: I found those definitions on : https://developer.apple.com/reference/foundation/nsjsonreadingoptions

My question is: Can someone please explain me differences between those options , what should I use them for and if you could show me some code example of those options it would be perfect :).

Any help appreciated.

Thanks.

like image 491
0ndre_ Avatar asked Oct 15 '16 10:10

0ndre_


People also ask

What is the purpose of JSONSerialization?

You use the JSONSerialization class to convert JSON to Foundation objects and convert Foundation objects to JSON. To convert a Foundation object to JSON, the object must have the following properties: The top level object is an NSArray or NSDictionary , unless you set the fragmentsAllowed option.

What kind of JSONSerialization have Readingoptions?

Reading OptionsSpecifies that leaf strings in the JSON object graph are mutable. Specifies that the parser allows top-level objects that aren't arrays or dictionaries. Specifies that reading serialized JSON data supports the JSON5 syntax.

What is JSONSerialization in Swift?

Swift version: 5.6. If you want to parse JSON by hand rather than using Codable , iOS has a built-in alternative called JSONSerialization and it can convert a JSON string into a collection of dictionaries, arrays, strings and numbers in just a few lines of code.

What is mutableContainers Swift?

mutableContainers ( NSJSONReadingMutableContainers ): In Swift, mutability is represented by var and let , so you have no need to use this option in Swifty codes. Only needed when you cast some parts of the deserialized result to NSMutableArray or NSMutableDictionary .


3 Answers

Short answer for the first two options:

Ignore them in Swift!

In Swift you can make objects mutable just with the var keyword.

In Objective-C on the other hand you need

  • NSJSONReadingMutableContainers to make the nested collection types mutable NSArrayNSMutableArray and NSDictionaryNSMutableDictionary.
  • NSJSONReadingMutableLeaves to make the value strings mutable → NSMutableString.

In both Objective-C and Swift if you are only reading the JSON you don't need mutability at all.

The third option NSJSONReadingAllowFragments is important if the root object of the received JSON is not an array and not a dictionary.
If it is an array or dictionary you can omit that option, too.

The pair of empty brackets [] represents No options (the options parameter can be omitted in Swift 3+).

like image 160
vadian Avatar answered Oct 17 '22 08:10

vadian


You'd better know how JSON values are imported into iOS world:

 JSON array ->  NSArray
 JSON object -> NSDictionary
 JSON number -> NSNumber
 JSON string -> NSString
 JSON true   -> NSNumber
 JSON false  -> NSNumber
 JSON null   -> NSNull

(You'd better also check the RFCs of JSON. RFC-4627, RFC-7159)

Then re-check the all options again:

mutableContainers (NSJSONReadingMutableContainers):

Guarantees the NSArrays or NSDictionarys contained in the result must be NSMutableArrays or NSMutableDictionarys. Someone says in older iOSs JSONSerialization (NSJSONSerialization) returned mutable objects without specifying mutableContainers, but depending on it is not recommended, and actually you can find someones reporting such code does not work in iOS 10.

In Swift, mutability is represented by var and let, so you have no need to use this option in Swifty codes. Only needed when you cast some parts of the deserialized result to NSMutableArray or NSMutableDictionary. I strongly recommend to rewrite such codes in a more Swifty manner.

mutableLeaves (NSJSONReadingMutableLeaves):

Guarantees the NSStrings contained in the result must be NSMutableStrings. Rarely used even in old Objective-C codes, ignore it.

allowFragments (NSJSONReadingAllowFragments):

In old RFC (RFC-4627), only array and object were valid as the outermost component of JSON. If you expect array or object (NSDictionary) from the server, NOT specifying this option would help you to find the invalid returned value from the server a little bit sooner.

Seeing the difference in codes:

Assume data1 is a valid UTF-8 representation of the following JSON:

[{"name": "aaa", "value": 123}, {"name": "bbb", "value": 456}]

And the code:

do {
    let result = try JSONSerialization.jsonObject(with: data1)
    let resultArray = result as! NSMutableArray //->This may cause your app crash
    //->Could not cast value of type '__NSArrayI' (0x105e79c08) to 'NSMutableArray' (0x105e79cd0).
    print(resultArray)
} catch {
    print(error)
}
 
do {
    let result = try JSONSerialization.jsonObject(with: data1, options: [.mutableContainers])
    let resultArray = result as! NSMutableArray //->This should always work
    print(resultArray) //->shows output...
} catch {
    print(error)
}

And data2:

-1

And the comparison for it:

do {
    let result = try JSONSerialization.jsonObject(with: data2)
    print(result)
} catch {
    print(error) //->Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
}

do {
    let result = try JSONSerialization.jsonObject(with: data2, options: [.allowFragments])
    print(result) //-> -1
} catch {
    print(error)
}
like image 42
OOPer Avatar answered Oct 17 '22 08:10

OOPer


Options: [] is an empty array returns nothing.

Whereas Options: [] can also be amend with:

  • NSJSONWritingOptions: for writing JSON data like.

    • NSJSONWritingOptions.NSJSONWritingPrettyPrinted: Specifies that the JSON data should be generated with whitespace designed to make the output more readable. If this option is not set, the most compact possible JSON representation is generated.
  • NSJSONReadingOptions: used when creating Foundation objects from JSON data.

    • NSJSONReadingOptions.MutableContainers: Specifies that arrays and dictionaries are created as mutable objects.
    • .mutableLeaves: Specifies that leaf strings in the JSON object graph are created as instances of NSMutableString.
    • .allowFragments: Specifies that the parser should allow top-level objects that are not an instance of NSArray or NSDictionary.
like image 25
vaibhav Avatar answered Oct 17 '22 10:10

vaibhav