How to parse JSON in Swift? - json

I have some JSON data that looks like this which I am trying to parse in Swift.
[
[
{
a: "1",
b: "2"
},
[
{
c: "3",
},
{
d: "4",
}
]
]
]
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
if let myArray = json[0] as? [[AnyObject]] {
for myObject in myArray {
print("This works!\(myObject)")
}
}
However nothing I try seems to work - any help would be appreciated.

you can use SwiftyJSON - https://github.com/SwiftyJSON/SwiftyJSON
or create a class based on your JSON scheme try to parse with it.
like:
class object
{
let data = Array<subObject>()
}
class subObject
{
let subData = Array<Dictionary<AnyObject,AnyObject>>()
}

This snippet is not JSON. If it was JSON, the keys would be strings, like this:
[
[
{
"a": "1",
"b": "2"
},
[
{
"c": "3",
},
{
"d": "4",
}
]
]
]
And anyway in your screenshot we see that your JSON has already been parsed!
What you show in the image is not JSON either, but an array containing arrays and dictionaries...
But let's say your JSON is actually valid and the missing quotes are just a copy/paste problem.
Then to achieve your goal you have to cast the result of NSJSONSerialization to the correct JSON format, then you can access the inner objects.
Like this, for example:
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [[AnyObject]] {
if let myArray = json.first {
for myObject in myArray {
print("This works!\(myObject)")
}
}
}
} catch let error as NSError {
print(error.localizedDescription)
}

Related

Load JSON in SwiftUI with arbitrary keys

I have a pretty simple JSON file I would like to load into a SwiftUI project. The JSON file looks like this:
{
"all": ["foo", "bar", "baz", ...],
"4": ["asd", "qwe", ...],
"25": ["something", "another", ...],
...
"2": ["xxx", "yyy", ...]
}
Pretty simple, a dictionary where each value is a list of strings. The keys are "all" and then an arbitrary number of integers such as "1", "123" and so on. They must not be in order, they can be any number, and there may be any number of them. So I don't know before hand how many keys there are.
I have managed to get this JSON into a variable of type String. But now I am stuck with how to parse this so I can for example fetch the list at key "all", or check if the key "123" exists and if so get that list.
How do I do that in SwiftUI?
Oh, and by the way, the string are Unicode and contain special characters like åäö.
try this approach:
struct ContentView: View {
#State var dataList: [String:[String]] = [:]
var body: some View {
List(Array(dataList.keys), id: \.self) { key in
Section(header: Text(key).foregroundColor(.red).font(.headline)) {
if let values = dataList[key] {
ForEach(values, id: \.self) { item in
Text("\(item)")
}
}
}
}
.onAppear {
let json = """
{
"all": ["foo", "bar", "baz"],
"4": ["asd", "qwe"],
"25": ["something", "another"],
"2": ["xxx", "yyy", "åäö"],
"åäö": ["qwerty", "uiop", "dfghjkh"]
}
"""
if let data = json.data(using: .utf8) {
do {
self.dataList = try JSONDecoder().decode([String: [String]].self, from: data)
} catch {
print("decode error: \(error)")
}
}
}
}
}

Casting dictionary of sets to JSON Object

I'm trying to build request body like this form:
{
"user": {
"id": 1,
"id": 2,
"id": 4
}
}
My first idea was built json from string and cast it to dictionary String and Any, but this solution have a issue. Some "id" are missing on casting by JSONSerialization step.
I tried to use:
var dictionary: [String : Any] = ["name" : "John"]()
var selectedIDs = Set<NSDictionary>()
// Adding values to selectedIDs set
let userIDDict = ["id" : id] as NSDictionary
selectedIDs.insert(userIDDict)
dictionary.updateValue(selectedIDs, forKey: "user")
But it cannot be cast by JSONSerialization (Invalid type in JSON write).
How can i resolve problem, which i'm facing?
Creating this request is not a problem; it's just not proper JSON, so you shouldn't try to use JSONSerialization. It's just a string, and so you can create that string:
let idKeyValues = ids.map { "\"id\": \($0)" }.joined(separator: ",\n ")
let request = """
{
"user": {
\(idKeyValues)
}
}
"""
===>
{
"user": {
"id": 1,
"id": 2,
"id": 4
}
}
The proper way to express this in JSON would be:
{
"user": {
"ids": [1, 2, 4]
}
}
With that, a Codable implementation should be very straightforward.

Swift 4 codable: the keys are Int array in JSON data

{
"0": {
"name": "legaldoc.pdf",
"cmisid": "yib5C-w92PPtxTBlXl4UJ8oDBthDtAU9mKN5kh2_KrQ"
},
"1": {
"name": "persdoc.pdf",
"cmisid": "dqAnrdNMXGTz1RbOMI37OY6tH9xMdxiTnz6wEl2m-VE"
},
"2": {
"name": "certdoc.pdf",
"cmisid": "6d7DuhldQlnb0JSjXlZb9mMOjxV3E_ID-ynJ0QRPMOA"
}
}
How do I use Swift 4 Codable to parse JSON data like that? the problem is that the keys are Int array.
How do I set CodingKeys for this?
As mentioned in the comments there is no array. All collection types are dictionaries.
You can decode it as Swift dictionary. To get an array map the result to the values of the sorted keys
let jsonString = """
{
"0": {
"name": "legaldoc.pdf",
"cmisid": "yib5C-w92PPtxTBlXl4UJ8oDBthDtAU9mKN5kh2_KrQ"
},
"1": {
"name": "persdoc.pdf",
"cmisid": "dqAnrdNMXGTz1RbOMI37OY6tH9xMdxiTnz6wEl2m-VE"
},
"2": {
"name": "certdoc.pdf",
"cmisid": "6d7DuhldQlnb0JSjXlZb9mMOjxV3E_ID-ynJ0QRPMOA"
}
}
"""
struct Item : Codable {
let name, cmisid : String
}
do {
let data = Data(jsonString.utf8)
let result = try JSONDecoder().decode([String: Item].self, from: data)
let keys = result.keys.sorted()
let array = keys.map{ result[$0]! }
print(array)
} catch {
print(error)
}

Parsing JSON response in Swift 3

I've got an API endpoint that returns JSON in the following format:
[
{
"id": "1",
"name": "John"
},
{
"id": "2",
"name": "Jane"
},
{
"id": "3",
"name": "Nick"
}
]
I am trying to parse this in Swift 3, but I can only find examples to parse JSON formatted like so:
{
"blogs": [
{
"needspassword": true,
"id": 73,
"url": "http://remote.bloxus.com/",
"name": "Bloxus test"
},
{
"needspassword": false,
"id": 74,
"url": "http://flickrtest1.userland.com/",
"name": "Manila Test"
}
],
"stat": "ok"
}
, which has an extra level above what mine does.
So, where examples I've seen are simply parsing their data like jsonResponse["blogs"], I can't do that as my format is different.
How can I parse the format I've got, or how can I return a format that is easier to parse?
Any suggestions appreciated, thanks!
You can just do the following :
let data = // Data received from WS
do {
let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions()) as? [[String : String]]
//json is now an array from dictionary matching your model
}
catch {
//handle error
}
This will parse it when placed in the network call.
do {
let json = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions()) as! [[String : AnyObject]]
let firstPerson = json[0]
print(firstPerson)
let id = firstPerson["id"] as! String
print(id)
let name = firstPerson["name"] as! String
print(name)
} catch {
//handle error
}
Also, I tend to be against advising third party libraries, but SwiftyJSON is an exception I make. If you want to try it, add this to your pod file:
pod SwiftyJSON', '3.0.0'
Documentation: https://github.com/SwiftyJSON/SwiftyJSON
EDIT - Answering Comment:
Replacement line:
if let id = firstPerson["id"] as? String {
print(id)
}
Replacement line (if you need to hold on to the value):
var thisId: String?
if let id = firstPerson["id"] as? String {
thisId = id
}
print(thisId ?? "")
i don't really know swift but there might be the equivalent of ajax json encoding (server side you json_encode your array and client side you json_decode the response)
the idea is to have the same formatter that encodes and decodes the data

Can't access JSON using SwiftyJSON

I am trying to access the JSON that I get via Alamofire:
func getDataFromServer() {
Alamofire.request(.POST, websiteURL, parameters: myParameters) .responseString {
(response) -> Void in
if let value = response.result.value {
let json = JSON(value)
self.parseJSON(json)
}
}
}
,and the JSON that is being returned to me looks something like this:
{
"status":"success",
"object":[
{
"name":"Bob",
"age":"20 ",
},
{
"name": "Jane",
"age":"25"
},
]
}
and I am using SwiftyJSON to access the names:
func parseJSON(json: JSON) {
for result in json["object"].arrayValue {
print(result["name"].stringValue)
}
}
but it is not printing anything. Am I doing something wrong?
responseJSON should be used instead of responseString
Your JSON is invalid
{
"status": "success",
"object": [
{
"name": "Bob",
"age": "20 ",
},
{
"name": "Jane",
"age": "25"
}, <--Delete this comma
]
}
Managed to figure out what was wrong with my code. When I did a POST request using Alamofire, I was returning the data back as a string: .responseString instead of JSON: .responseJSON
working code:
func getDataFromServer() {
Alamofire.request(.POST, websiteURL, parameters: myParameters) .responseJSON {
(response) -> Void in
if let value = response.result.value {
let json = JSON(value)
self.parseJSON(json)
}
}
}
Replace responseString with responseJSON