Cannot convert empty array of arrays to JSON with Swift 2 - ios

What is wrong with this piece of code (which was inspired by this example)? It currently prints JSON string "(<5b5d>, 4)" instead of the expected "[]".
var tags: [[String]] = []
// tags to be added later ...
do {
let data = try NSJSONSerialization.dataWithJSONObject(tags, options: [])
let json = String(data: data, encoding: NSUTF8StringEncoding)
print("\(json)")
}
catch {
fatalError("\(error)")
}

Short answer: The creation of the JSON data is correct. The problem is in the
conversion of the data to a string, what you want is the NSString method:
let json = NSString(data: data, encoding: NSUTF8StringEncoding) as! String
which produces the expected [].
Slightly longer answer:
Your code
let json = String(data: data, encoding: NSUTF8StringEncoding)
calls the String init method
/// Initialize `self` with the textual representation of `instance`.
/// ...
init<T>(_ instance: T)
and the result is the textual representation of the tuple
(data: data, encoding: NSUTF8StringEncoding):
(<5b5d>, 4)
Actually you can call String() with arbitrary arguments
let s = String(foo: 1, bar: "baz")
print(s) // (1, "baz")
in Swift 2. This does not compile in Swift 1.2, so I am not sure if
this is intended or not. I have posted a question in the
Apple Developer Forums about that:
String init accepts arbitrary arguments.

Related

Removing unnecessary JSON spaces

I have encoded a Codable object:
let encodedData = try JSONEncoder().encode(someObject)
And I print the JSON by doing the following (I know its not safe, I'm just testing):
let json = try! JSONSerialization.jsonObject(with: encodedData)
print("JSON: \(json)")
My JSON has lots of spaces. I want a way to remove these spaces, to save space on the encoded String. You can tell that it looks quite different from a normal JSON due to these spaces.
JSON (part of it):
How can I reduce the spaces to reduce the bytes this takes up?
As #Martin R pointed out, I was not printing the JSON properly. It should have instead been:
let jsonString = String(data: encodedData, encoding: .utf8)!
print(jsonString)
The result looks like so:
{"type":1,"modifiers":[],"parameters":{ ...
This printed data can then be decoded in the future like so:
let data = Data(jsonString.utf8)
let someResult = try JSONDecoder().decode(SomeType.self, from: data)

How do I stop Swift from injecting escaped single quotes in my [String]?

I'm attempting to print out a string array without escaped single quotes. For some reason, Swift is injecting escaped single quotes when printing my array. This has a trickle down problem when I use the array to build JSON. JSON ends up not being able to parse due to the escaped single quotes.
I thought this was a problem with my code, but I've distilled this down to a single usecase that should be straightforward.
let names = ["Tommy 'Tiny' Lister", "Tom Hanks"]
print(names)
The output is:
["Tommy \'Tiny\' Lister", "Tom Hanks"]
Note: I did not include escaped single quotes in my names array.
How do I prevent this from happening?
Here is the what I'm doing later in code to create JSON. For purposes of brevity, this is a really dumbed down version of what I'm doing:
var names = ["Tommy Tiny Lister", "Tom Hanks"]
var jsonString = """
{"names": \(names)}
"""
var jsonData = jsonString.data(using: .utf8)
if let json = try? JSONSerialization.jsonObject(with: jsonData!) as? [String: Any] {
let jsonData = try! JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
let string = String(data: jsonData, encoding: .utf8)
print(string!)
}
What you are doing is using Swift arrays' description to generate JSON:
var jsonString = """
{"names": \(names)}
""" // your JSON will contain name.description
You are relying on the fact that the implementation of description just so happens to result in the same format as JSON most of the time. As you can see, when there are ' in the array elements, the description is not valid JSON.
Basically, you should not rely on the description to generate JSON. Instead, you should use Codable to generate JSON data from a Swift array.
For the JSON you want to produce:
{
"names": ["Tommy 'Tiny' Lister", "Tom Hanks"]
}
You can use a struct like this:
struct Names : Codable {
let names: [String]
}
And then you can produce JSON Data like this:
let encoder = JSONEncoder()
do {
let obj = Names(names: ["Tommy 'Tiny' Lister", "Tom Hanks"])
let data = try encoder.encode(obj)
} catch { ... }

Swift Alamofire Escape a JSON

I am working with swift Alamofire, but i had an issue, i want pass data to the server but the server required escaped JSON string, like this
{\"status\":1,\"id\":\"1bcc3331b09d32f7439ad9d5f2acfb35\",\"progress\":[{\"airline_code\":\"SRI\",\"ctr\":0,\"rate\":5,\"state\":1,\"data\":null}]}
but I have this data from the response:
{"status":1,"id":"1bcc3331b09d32f7439ad9d5f2acfb35","progress":[{"airline_code":"SRI","ctr":0,"rate":5,"state":1,"data":null}]}
how can I convert JSON to escaped JSON like that,
I have tried this online converter
Converter Escape JSON
and its works perfect, how can I escape like that in swift Xcode.
update complete json (look inside feed: )
{
"flight_child":"0",
"child":"[]",
"depart_hidden_transit":"0",
"depart_adult_surcharge":"0",
"depart_flight":"[{\"airlineCode\":\"LIO\",\"arriveCity\":\"Jakarta Soekarno Hatta\",\"arriveDate\":\"2018-04-28\",\"arriveDatetime\":\"2018-04-28 20:05\",\"arrivePort\":\"CGK\",\"arriveTime\":\"20:05\",\"arriveTimezone\":7.0,\"departCity\":\"Yogyakarta\",\"departDate\":\"2018-04-28\",\"departDatetime\":\"2018-04-28 18:50\",\"departPort\":\"JOG\",\"departTime\":\"18:50\",\"departTimezone\":7.0,\"flightNumber\":\"JT 555\",\"stopCount\":0}]",
"auth_mode":"",
"flight_infant":"0",
"flight_to":"CGK",
"flight_return":"",
"depart_child_discount":"0",
"infant":"[]",
"depart_choice":"d3ea46551c769f462c3e1a4dd25c933d",
"depart_child_surcharge":"0",
"version_code":"3",
"contact_email":"mul#gmai.oc",
"contact_name":"Mulia RIfai",
"adult":"[[\"Mr\",\"Muhammad Fuad\",null,null,\"0\",null,null,null,null,null]]",
"flight_trip":"oneway",
"flight_adult":"1",
"depart_adult_discount":"0",
"contact_phone":"0972312",
"depart_carrier":"LIO",
"client_password":"arena123",
"depart_infant_discount":"0",
"depart_infant_surcharge":"0",
"client_username":"androidarena",
"flight_depart":"2018-05-03",
"feed":"{\"status\":1,\"id\":\"1bcc3331b09d32f7439ad9d5f2acfb35\",\"progress\":[{\"airline_code\":\"SRI\",\"ctr\":0,\"rate\":5,\"state\":1,\"data\":null}]}",
"contact_title":"Mr.",
"flight_from":"JOG",
"depart_class":"eco",
"device_id":"123456789011123"
}
Even though this should be fixed by the server. A nasty hack would be to first stringify your json that should be passed as the string and then replacing the occurrence of double quotation with \".
let dic = ["status":1,
"id":"1bcc3331b09d32f7439ad9d5f2acfb35",
"progress":[["airline_code":"SRI","ctr":0,"rate":5,"state":1,"data":nil]
]
] as [String : Any]
if let json = try? JSONSerialization.data(withJSONObject: dic, options: JSONSerialization.WritingOptions.init(rawValue: 0)) {
if let str = String(data: json, encoding: String.Encoding.utf8)?.replacingOccurrences(of: "\"", with: "\\\"") {
print(str)
}
}
Result:
{\"id\":\"1bcc3331b09d32f7439ad9d5f2acfb35\",\"status\":1,\"progress\":[{\"state\":1,\"airline_code\":\"SRI\",\"data\":null,\"ctr\":0,\"rate\":5}]}

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)

Encoding/decoding arbitrary binary data to string in swift/objective-c

I need to encode/decode an arbitrary NSData object into a String/NSString. Here's what I have for encoding:
var avatar64 = self.avatar.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.fromRaw(0)!);
let avatarData = NSData(base64EncodedString: avatar64, options: NSDataBase64DecodingOptions.fromRaw(0)!);
let avatar = NSString(data: avatarData, encoding: NSUTF8StringEncoding);
But avatar is nil. What am I doing wrong?
Your first step already creates a Base64-encoded string of the data in self.avatar:
var avatar64 = self.avatar.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.fromRaw(0)!);
Your second step decodes the Base64 string again, so that avatarData contains the same
binary data as your original self.avatar:
let avatarData = NSData(base64EncodedString: avatar64, options: NSDataBase64DecodingOptions.fromRaw(0)!);
Finally, your third step tries to create a string from the original (binary) data:
let avatar = NSString(data: avatarData, encoding: NSUTF8StringEncoding);
This fails because the data is not a valid UTF-8 sequence.
In short: Just remove the third and second line.

Resources