CREATE JSON SWIFTYJSON - swift

I am trying to create a json like this
[
{"key": "value"},
{"key": "value"},
{"key": "value"}
]
this is my code
var array: JSON = []
for i in (0..<obj.count){
array = [
"user": obj[i].name!,
"apikey": obj[i].key!
]
}
But when I try to print, only I get with the first item,
How can I resolve that

Use Codable. Since Swift 4 SwiftyJSON became obsolete
struct Object : Encodable {
private enum CodingKeys : String, CodingKey { case name = "user", key = "apikey" }
let name, key : String
}
let obj = [Object(name: "Foo", key: "API123"), Object(name: "Bar", key: "API456")]
do {
let jsonData = try JSONEncoder().encode(obj)
let jsonString = String(data: jsonData, encoding: .utf8)!
print(jsonString)
} catch { print(error) }

Related

Getting key from Dictionary into neasted Decodable model

Let's say we have a JSON like that:
{
"id1": {
"name": "hello"
},
"id2": {
"name": "world"
}
}
A model:
struct Model: Decodable {
var id: String
var name: String
}
How is it possible to make an array of Model from the JSON above?
You could do something like this
let data = """
{
"id1": {
"name": "hello"
},
"id2": {
"name": "world"
}
}
""".data(using: .utf8)!
struct Name: Decodable {
let name: String
}
struct Model {
let id: String
let name: String
}
do {
let json = try JSONDecoder().decode([String: Name].self, from: data)
let result = json.map { Model(id: $0.key, name: $0.value.name) }
print(result)
} catch {
print(error)
}
We decode the data as [String, Name]. We could decode it as [String: [String:String]] but this will mean that we will have to handle optional values so it is easier to create a Name struct to handle that part.
Once we have the dictionary we map over it converting it into the model object, leaving an array of [Model]

How to make a struct with `variable: [String: Codable]` codable?

I got a struct like the following
struct Wrapper {
var value: [String: Any]
// type "Any" could be String, Int or [String].
// i.g. ["a": 1, "b": ["ccc"]]
// and the keys of this dictionary are not determined
}
I been struggled for quite a while😭.
Anyone has any idea how to resolve it?
You can use some library like AnyCodable
Then you can make your struct Codable by using AnyCodable class instead of Any.
struct Wrapper: Codable {
var value: [String: AnyCodable]
}
Example
let arrayWrapper: [String: Any] =
["value" :
[
"test" : ["1", "2", "3"],
"parse" : ["4", "5", "6"]]
]
let jsonData = try! JSONSerialization.data(withJSONObject: arrayWrapper, options: .prettyPrinted)
do {
let decoder = JSONDecoder()
let result = try decoder.decode(Wrapper.self, from: jsonData)
print("result:", result)
} catch let error {
print("error:", error)
}
Output
result: Wrapper(value: ["parse": AnyCodable(["4", "5", "6"]), "test": AnyCodable(["1", "2", "3"])])

Swift - Expected to decode Array<Any> but found a dictionary instead.”, underlyingError: nil

I'm trying to decode some json for my application and I usually do this.
My struct;
struct RequestTypes: Codable {
let MerchRequestTypeID: Int?
let TypeName: String?
let LayoutID: Int?
private enum CodingKeys: Int, CodingKey {
case MerchRequestTypeID
case TypeName
case LayoutID
}
}
And decoding;
func downloadRequestTypesJson(){
guard let gitUrl = URL(string: "URL") else { return }
URLSession.shared.dataTask(with: gitUrl) { (data, response
, error) in
guard let data = data else { return }
do {
let decoder = JSONDecoder()
let RequestData = try decoder.decode(Array<RequestTypes>.self, from: data)
DispatchQueue.main.sync {
print(RequestData[0].MerchRequestTypeID)
print(RequestData[1].MerchRequestTypeID)
print(RequestData[2].MerchRequestTypeID)
}
} catch let err {
print("Err", err)
}
}.resume()
}
This works fine for below json;
[
{
"MerchRequestTypeID": 1,
"TypeName": "Stok",
"LayoutID": 1
},
{
"MerchRequestTypeID": 2,
"TypeName": "Stand",
"LayoutID": 2
},
{
"MerchRequestTypeID": 3,
"TypeName": "Eğitim",
"LayoutID": 2
}
]
But now I need to decode this json and im getting Expected to decode Array but found a dictionary instead. error;
{
"RequestTypes": [
{
"MerchRequestTypeID": 1,
"TypeName": "Stock",
"LayoutID": 1
},
{
"MerchRequestTypeID": 2,
"TypeName": "Stand",
"LayoutID": 2
},
{
"MerchRequestTypeID": 3,
"TypeName": "Education",
"LayoutID": 2
}
]
}
Couldn't be able to find proper way to do this. Any help is appreciated.
Edit: I am beginner on Swift. I want to know how to decode second json and how to reach its elements.
That's because you are trying to decode a JSON object with a "RequestTypes" property and not an array. One solution is to create a new struct for this data structure and use that to decode your JSON:
struct RequestTypesContainer: Codable {
let RequestTypes : [RequestTypes]
private enum CodingKeys: String, CodingKey {
case RequestTypes
}
}
And then:
let RequestData = try decoder.decode(RequestTypesContainer.self, from: data)

Swift Codable: decode dictionary with unknown keys

Codable is great when you know the key formatting of the JSON data. But what if you don't know the keys? I'm currently faced with this problem.
Normally I would expect JSON data to be returned like this:
{
"id": "<123>",
"data": [
{
"id": "<id1>",
"event": "<event_type>",
"date": "<date>"
},
{
"id": "<id2>",
"event": "<event_type>",
"date": "<date>"
},
]
}
But this is what I'm aiming to decode:
{
"id": "123",
"data": [
{ "<id1>": { "<event>": "<date>" } },
{ "<id2>": { "<event>": "<date>" } },
]
}
Question is: how do I use Codable to decode JSON where the keys are unique? I feel like I'm missing something obvious.
This is what I'm hoping to do so I can use Codable:
struct SampleModel: Codable {
let id: String
let data: [[String: [String: Any]]]
// MARK: - Decoding
enum CodingKeys: String, CodingKey {
case id = "id"
case data = "data"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
// This throws an error: Ambiguous reference to member 'decode(_:forKey:)'
data = try container.decode([[String: [String: Any]]].self, forKey: .data)
}
}
This throws an error: Ambiguous reference to member 'decode(_:forKey:)'
For your completely changed question, the solution is very similar. Your struct simply adds one additional layer above the array. There's no need for any custom decoding nor even any CodingKeys.
Note that you can't use Any in a Codable.
let json="""
{
"id": "123",
"data": [
{ "<id1>": { "<event>": "2019-05-21T16:15:34-0400" } },
{ "<id2>": { "<event>": "2019-07-01T12:15:34-0400" } },
]
}
"""
struct SampleModel: Codable {
let id: String
let data: [[String: [String: Date]]]
}
var decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
do {
let res = try decoder.decode(SampleModel.self, from: json.data(using: .utf8)!)
print(res)
} catch {
print(error)
}
The original answer for your original question.
Since you have an array of nested dictionary where none of the dictionary keys are fixed, and since there are no other fields, you can just decode this as a plain array.
Here's an example:
let json="""
[
{ "<id1>": { "<event>": "2019-07-01T12:15:34-0400" } },
{ "<id2>": { "<event>": "2019-05-21T17:15:34-0400" } },
]
"""
var decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
do {
let res = try decoder.decode([[String: [String: Date]]].self, from: json.data(using: .utf8)!)
print(res)
} catch {
print(error)
}

Swift Codable with Different Array Types

I'm writing a program where I'm parsing JSON data that includes array of arrays, where the nested arrays have different object types (specifically, [[String, String, Int]]). For example,
{
"number": 5295,
"bets": [
[
"16",
"83",
9
],
[
"75",
"99",
4
],
[
"46",
"27",
5
]
]
}
I'm trying to use codable to help me parse the data, but when I try something like
struct OrderBook: Codable {
let number: Int
let bets: [Bet]
}
struct Bet: Codable {
let price: String
let sale: String
let quantity: Int
}
it gives me errors saying that
Expected to decode Dictionary<String, Any> but found an array instead
How do I get around this? I can't declare an array of empty type.
One solution (assuming you can't change the JSON) is to implement custom decoding logic for Bet. You can use an unkeyed container (which reads from a JSON array) in order to decode each of the properties in turn (the order in which you call decode(_:) is the order they're expected to appear in the array).
import Foundation
struct OrderBook : Codable {
let number: Int
let bets: [Bet]
}
struct Bet : Codable {
let price: String
let sale: String
let quantity: Int
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
self.price = try container.decode(String.self)
self.sale = try container.decode(String.self)
self.quantity = try container.decode(Int.self)
}
// if you need encoding (if not, make Bet Decodable
// and remove this method)
func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
try container.encode(price)
try container.encode(sale)
try container.encode(quantity)
}
}
Example decoding:
let jsonString = """
{ "number": 5295, "bets": [["16","83",9], ["75","99",4], ["46","27",5]] }
"""
let jsonData = Data(jsonString.utf8)
do {
let decoded = try JSONDecoder().decode(OrderBook.self, from: jsonData)
print(decoded)
} catch {
print(error)
}
// OrderBook(number: 5295, bets: [
// Bet(price: "16", sale: "83", quantity: 9),
// Bet(price: "75", sale: "99", quantity: 4),
// Bet(price: "46", sale: "27", quantity: 5)
// ])