Invalid type in JSON write (__SwiftValue) - ios

I am trying to pass a Parameters [String:Any] value to JSONSerialization.data and it's throwing error every time.
I know the values of the [String:Any] dictionary is Swifty.JSON objects. But I am not able to convert them to NSDictionary object.
I populate the params from another dictionary like so:
var params = [String:Any]()
for (key, value) in self.myDictionary[self.selectedEntry] as! JSON {
print("\(key) - \(value.description)")
params[key]=value
}
And this is whats inside the params object after a print(params).
["searchOptions": {
"omit_saved_records" : false
}, "customFilters": {
"is_next_sellers_search" : "Y"
}, "use_code_std": [
"RSFR",
"RCON"
]]
I am passing the params to this function:
let json = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
This is where the error occur.
I am expecting this to simply work but I get this error instead:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (__SwiftValue)'
What am I doing wrong here?

The JSON type of SwiftyJSON is a custom type and cannot be serialized.
Just get the dictionaryObject from the JSON object
if let params = self.myDictionary[self.selectedEntry].dictionaryObject {
And don't prettyPrint. The server doesn't care
let json = try JSONSerialization.data(withJSONObject: params)
Note: You are encouraged to drop SwiftyJSON in favor of Codable.

Related

Alamofire 5.5 responseDecodable on JSON array

I am trying to decode an api response that just responds with an array. All the examples I see for using responseDecodable are a dictionary with a data key or something. But when I just pass [Movie].self into as the decoder I get:
failure(Alamofire.AFError.responseSerializationFailed(reason: Alamofire.AFError.ResponseSerializationFailureReason.decodingFailed(error: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "name", intValue: nil), Swift.DecodingError.Context(codingPath: responseDecodable
I'm assuming I'm not doing this right, looking for some help
GET /request
Response:
[{"id": 1, "name": "test"}]
struct Movie: Codable, Hashable {
let id: Int
let name: String
}
AF.request("http://localhost/request", parameters: parameters)
.responseDecodable(of: [Movie].self) { response in
debugPrint(response)
}
You will need to first assign a variable to accept the JSON data. From there, you can display the result. To illustrate:
AF.request("http://localhost/request", parameters: parameters)
.responseDecodable(of: [Movie].self) { response in
let myresult = try? JSON(data: response.data!)
then print it:
debugPrint(myresult)
If your JSON data is sound, then you should have no problem receiving the data. If your JSON is nested, then, you can drill-down into it:
let myresult = try? JSON(data: response.data!)
let resultArray = myresult!["result"]
and so on.
As for the "KeyNotFound" error ... It's because of what you said ... it's looking for a dictionary key/value pair. That should be resolved once you try the above example. Also, it's good practice to place your "method" in your AF request. :)
According to the error, your JSON didn't return a name value, so check that's it's actually supposed to be that key, or mark the value as optional if it's not always returned. let name: String?

Swift showing error when serializing data

When I try to serialize json data in swift I get this error
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (__SwiftValue)'
Here is the code that is creating this issue:
request.httpBody = try? JSONSerialization.data(withJSONObject: data, options: [])
my data variable looks something like this:
let data = ["first_name": "John", "last_name": "Riverson", "post_info: userPost(title: "Some title", date_published: "some date")] as [String: Any]
I issue is caused due to the userPost struct, but I am not sure how to fix it.
It seems the result of userPost is not available for JSON.
According to JSONSerialization
A Foundation object that may be converted to JSON must have the following properties:
The top level object is an NSArray or NSDictionary.
All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
All dictionary keys are instances of NSString.
Numbers are not NaN or infinity
If you want to make userPost could be accpeted by JSONSerialization, refer to Using JSON with Custom Types, and apply Codable to it.
Your analysis is correct that it's due to the struct.
As per the documentation on JSONSerialization:
Foundation object that may be converted to JSON must have the
following properties:
The top level object is an NSArray or NSDictionary.
All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
All dictionary keys are instances of NSString.
Numbers are not NaN or infinity.
Ref:
https://developer.apple.com/documentation/foundation/jsonserialization
So you will need to convert the struct to dictionary to insert it here.
Something like:
let userPostDict: [String:Any] = //... your logic e.g. userPost.toDictionary
let data = ["first_name": "John",
"last_name" : "Riverson",
"post_info" : userPostDict]
You could have a toDictionary computed property inside your userPost struct that gives you a [String:Any]
Example:
extension YourStruct {
var toDictionary: [String:Any] {
//make the dictionary & return here
}
}

Parse an object returned as JSON from API in swift

I have recieved a response object (res) in swift from REST API. It is of type. __NSArrayM. It contains a JSON format string which I want to parse.
{ JsonResult = "[ { \"IsAuth\":\"true\" } ]"; }
It is a long JSON String and I have shortened it for simplicity.
To parse a json, the object needs to be of type Dictionary but I can't cast the object of type __NSArrayM into it.
I searched a lot but can't figure out anyway to read this JSON string.
Additional: Whichever object I try to cast the response object. I get the error -
Could not cast value of type '__NSArrayM' (0x107e86c30) to 'NSData' (0x107e86168) or whichever data type I cast into.
Let's do this step by step.
You say you have an object named "res" which is of type __NSArrayM and which contains this thing:
{ JsonResult = "[ { \"IsAuth\":\"true\" } ]"; }
It means that you already have converted the JSON to an object, namely an NSArray.
In this array that we don't see, this thing you're showing us is a dictionary (that we will name "dict") with its value being a String which itself represents another JSON object.
Let's get the value using the key:
if let value = dict["JsonResult"] as? String {
print(value)
}
Now "value" is supposed to be "[ { \"IsAuth\":\"true\" } ]".
This is a String which represents JSON. To decode the JSON, we first have to make the string into data then we can decode:
if let data = value.data(using: .utf8) {
if let content = try? JSONSerialization.jsonObject(with: data, options: []),
let array = content as? [[String: Any]]
{
print(array)
}
}

How do I store serialize an NSDictionary with NSJSONSerialization when one of the values is NSData?

Take this simplified example:
let dict: [String: AnyObject] = ["foo": ("bar" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!9]
let json = try! NSJSONSerialization.dataWithJSONObject(dict, options: [])
I cannot get that to run, it crashes with:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (NSConcreteMutableData)'
I need to send a block of JSON to my server, where some values are strings and some are NSData. What am I doing wrong?
It's worth your time to read through the JSON RFC. Note:
JSON can represent four primitive types (strings, numbers, booleans, and null) and two structured types (objects and arrays).
JSON can't represent raw data, so you'll need to convert the NSData to one of those other types (typically a string). One common approach is:
let stringFromData = NSString(data: data, encoding: NSUTF8StringEncoding)
Just make sure you and your server agree on which encoding you'll use.
If you have a lot of these, you can map through your dictionary and convert them at once. There are a few possible implementations depending on your structure; here's one approach:
let dictWithString = dict.map { (key, value) -> (String, NSObject) in
if let value = value as? NSData {
return (key, NSString(data: value, encoding: NSUTF8StringEncoding)!)
}
return (key, value)
}
You can also convert your NSData into Base64 Encoded string in order to set to your json content.
let base64String = rawData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
and decoding:
let rawData = NSData(base64EncodedString: base64String, options: .IgnoreUnknownCharacters)

Could not cast value of type '__NSArrayM' to 'NSDictionary'

I have a json.I am trying to parse that with that code.But its says
Could not cast value of type '__NSArrayM' to 'NSDictionary'
do {
let dataDictionary: NSDictionary = try NSJSONSerialization.JSONObjectWithData(responseObject as! NSData, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary // <------ Error
if let customerArray = dataDictionary.valueForKey("cart") as? NSArray {
for js in customerArray {
let nameArray = js.valueForKey("name")
let idArray = js.valueForKey("id")
}
}
}
Thank you for your helps
The root object in your data is an array, not a object (dictionary).
You need to dynamically decide how to handle your JSON depending on the deserialized object.
What it's telling you is that the JSON object that you're parsing is not a dictionary, it's an array. So if you change it so that you treat its value as an array instead of a dictionary, you'll be able to iterate over that.
You need to reevaluate your JSON to ensure that it's structured the way you think it is. It would also be useful if you posted the JSON that you're trying to parse so that we can see it's structure as well.

Resources