How does the swift 4 Decodable protocol work with the ' - ' letter?
For example:
[{
"trigger": {
"url-filter": "webkit.org",
"resource-type": ["image"]
},
"action": {
"selector": "#logo",
"type": "block"
}
}]
In My Swift Class:
struct blockerJson : Decodable {
let action : action
let trigger : trigger
struct action : Decodable {
let selector : String
let type : String
}
struct trigger : Decodable {
let urlFilter : String
let resourceType : String
}
}
I don't know how to change the class, but the json can't change...
This code parses trigger block
struct Trigger: Decodable {
var urlFilter: String
var resourceType: [String]
enum CodingKeys: String, CodingKey {
case urlFilter = "url-filter"
case resourceType = "resource-type"
}
}
Related
I have a Json in which there is the possibility that a few keys can be missing
Full JSON looks like this
{
"data": "some text",
"id": "3213",
"title": "title",
"description": "description",
"customObj1": [{
"id": "2423",
"count": 35
........
.......
}]
"customObj2": [{
"number": "2423",
"name": "john"
........
.......
}]
"customObj3": [{
"like": "2423",
"Other": 9
........
.......
}]
}
the custom object (1,2,3) may or may not be available in JSON, How can I write the model in swift using codable and struct?
here is how the model (dummy) look like
// MARK: - Response
struct Response: Codable {
let data, id, title, ResponseDescription: String
let customObj1: [CustomObj1]
let customObj2: [CustomObj2]
let customObj3: [CustomObj3]
enum CodingKeys: String, CodingKey {
case data, id, title
case ResponseDescription = "description"
case customObj1, customObj2, customObj3
}
}
// MARK: - CustomObj1
struct CustomObj1: Codable {
let id: String
let count: Int
}
// MARK: - CustomObj2
struct CustomObj2: Codable {
let number, name: String
}
// MARK: - CustomObj3
struct CustomObj3: Codable {
let like: String
let other: Int
enum CodingKeys: String, CodingKey {
case like
case other = "Other"
}
}
I have tried using decode init but need help
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
if (values.contains(. customObj1)) {
// here I need help }
else {
self.category = nil
}
}
}
I try to Post Json with alamofire, which I can, but I need a value that I get from the result of that successful API post. how do I get value from post method JSON in swift? i use Alamofire to make things simple.
{
"phoneNum": "+1234566869",
"phoneNumTarget": "+2345687960",
"id": "79999000"
}
so this is the body parameter for my Post JSON,
and this is the result of a successful post JSON
{
"data": {
"orderId": "79999000",
"uniquesRoomId": 12341414,
"users": [
{
"avatar_url": "https:// some web",
"phone_number": "085858490282",
"fullname": "BuzzLightyear"
},
{
"avatar_url": "https:// some web",
"phone_number": "085858490282",
"fullname": "General Zurg"
}
],
"chat_name": "user2"
},
"message": "room has been successfully created",
"success": true
}
Now I want to retrieve all the value that I get from that post Json method, how do I do it? do I need to make a struct first like when I want to make get method request for JSON?
*update question
let data : [DataClass] = [ ]
AF.request(web, method: .post, parameters: chataja,encoder:
JSONParameterEncoder.default).responseJSON { (response) in
switch (response.result) {
case.success :
self.data = response
break
i try for this and it getting some error
You need to parse this response through Decodable confirmed structs
import Foundation
// MARK: - User
struct User: Codable {
let data: DataClass
let message: String
let success: Bool
}
// MARK: - DataClass
struct DataClass: Codable {
let orderID: String
let uniquesRoomID: Int
let users: [UserElement]
let chatName: String
enum CodingKeys: String, CodingKey {
case orderID = "orderId"
case uniquesRoomID = "uniquesRoomId"
case users
case chatName = "chat_name"
}
}
// MARK: - UserElement
struct UserElement: Codable {
let avatarURL: String
let phoneNumber, fullname: String
enum CodingKeys: String, CodingKey {
case avatarURL = "avatar_url"
case phoneNumber = "phone_number"
case fullname
}
}
AF.request(web, method: .post, parameters: chataja,encoder:
JSONParameterEncoder.default).responseJSON { (response) in
switch (response.result) {
case .success(let data) :
let user = try? JSONDecoder().decode(User.self, from: data)
Okay, so I am stuck at decoding the last item of this particular json by this the model, "payload" is always nil, Inside this "payload" object I can make my own json structure, I am able to decode the "text" but when it comes to the last item which is "payload", it is not working and is always nil.
I am not using any third-party library.
My Model Class.
struct DailougeFlowModel : Decodable {
// private enum CodingKeys : String, CodingKey {
// case responseId = "responseId"
// case queryResult = "queryResult"
// }
let responseId : String?
let queryResult : QueryResult?
}
struct QueryResult: Decodable {
// private enum CodingKeys : String, CodingKey {
// case fulfillmentText = "fulfillmentText"
// case fulfillmentMessages = "fulfillmentMessages"
// }
let fulfillmentText : String?
let fulfillmentMessages : [FulfillmentMessages]?
}
struct FulfillmentMessages: Decodable {
let text : TextModel?
let payLoad : Questions?
}
struct TextModel: Decodable {
let text : [String]?
}
struct Questions : Decodable{
let questions : [String]?
}
This json is what I am getting from the dailogeflow(V2). I am integrating a chatbot in the application.
{
"responseId": "2b879f78-cc05-4735-a7e8-067fdb53a81d-f6406966",
"queryResult": {
"fulfillmentMessages": [
{
"text": {
"text": [
"Text Here"
]
}
},
{
"text": {
"text": [
"Another Reply For Hi"
]
}
},
{
"payload": {
"questions": [
"Question One",
"Question Two",
"Question Three",
"Question Four"
]
}
}
]
}
}
Specify the inner model names as it is in the json response, if you want to specify your own model name then you would need to set an enum in each model just like the first model 'ResponseModel'
// MARK: - ResponseModel
struct ResponseModel: Codable {
let responseID: String
let queryResult: QueryResult
enum CodingKeys: String, CodingKey {
case responseID = "responseId"
case queryResult
}
}
// MARK: - QueryResult
struct QueryResult: Codable {
let fulfillmentMessages: [FulfillmentMessage]
}
// MARK: - FulfillmentMessage
struct FulfillmentMessage: Codable {
let text: Text?
let payload: Payload?
}
// MARK: - Payload
struct Payload: Codable {
let questions: [String]
}
// MARK: - Text
struct Text: Codable {
let text: [String]
}
I'm trying to decode this json but certain variables are nil. Most of these seem to be okay it's just a few that are not working properly. I don't have much experience with swift so I'm kind of at a loss of what to try next.
mycode:
struct Attr : Decodable {
let page: String?
let perpage: String?
let totalpages: String?
let total: String?
}
struct Images : Decodable {
let text: String?
let size: String?
}
struct Artist : Decodable {
let name: String?
let mbid: String?
let url: String?
}
struct Streamable : Decodable {
let text: String?
let fulltrack: String?
}
struct Track : Decodable {
let name: String?
let duration: String?
let playcount: String?
let listeners: String?
let mbid: String?
let url: String?
let streamable: Streamable?
let artist: Artist?
let images: [Images]?
}
struct Tracks : Decodable {
let track:[Track]?
}
struct Container : Decodable {
let tracks: Tracks?
let attr: Attr?
}
json:
{
"tracks": {
"track": [
{
"name": "bad guy",
"duration": "0",
"playcount": "870682",
"listeners": "125811",
"mbid": "",
"url": "https://www.last.fm/music/Billie+Eilish/_/bad+guy",
"streamable": {
"#text": "0",
"fulltrack": "0"
},
"artist": {
"name": "Billie Eilish",
"mbid": "",
"url": "https://www.last.fm/music/Billie+Eilish"
},
"image": [
{
"#text": "https://lastfm-img2.akamaized.net/i/u/34s/88d7c302d28832b53bc9592ccb55306b.png",
"size": "small"
},
{
"#text": "https://lastfm-img2.akamaized.net/i/u/64s/88d7c302d28832b53bc9592ccb55306b.png",
"size": "medium"
},
{
"#text": "https://lastfm-img2.akamaized.net/i/u/174s/88d7c302d28832b53bc9592ccb55306b.png",
"size": "large"
},
{
"#text": "https://lastfm-img2.akamaized.net/i/u/300x300/88d7c302d28832b53bc9592ccb55306b.png",
"size": "extralarge"
}
]
},
...
images should contain an array of Images instead of nil, the majority of the other variables seem to be okay though
This is because when dealing with decodable the keys used in your serialized data format have to match the property names; In your case, the Image type contains text and size properties but the json contains #text and size (text =/= #text); That's also applicable for the type name Images not image.
However, citing from Encoding and Decoding Custom Types:
If the keys used in your serialized data format don't match the
property names from your data type, provide alternative keys by
specifying String as the raw-value type for the CodingKeys
enumeration.
Add CodingKeys as:
struct Images : Decodable {
let text: String?
let size: String?
enum CodingKeys: String, CodingKey {
case text = "#text"
case size
}
}
Tip: it is useful to use try/catch when facing an error while decoding your data:
do {
let result = try JSONDecoder().decode(Images.self, from: data)
} catch {
print(error.localizedDescription)
}
At this point it would print the error which might helpful to understand the issue most of the time.
Add CodingKey enum to map fields with # in the name
struct Images : Decodable {
let text: String?
let size: String?
enum CodingKeys: String, CodingKey {
case text = "#text"
case size
}
}
struct Streamable : Decodable {
let text: String?
let fulltrack: String?
enum CodingKeys: String, CodingKey {
case text = "#text"
case fulltrack
}
}
You also have an error in your Trackstruct, change images to image (or use CodingKey mapping there to). For more on decoding json see Apple's doc
With the json below, is it possible to get those keys under "fields" and print out one by one using for loop. (path, public_key, icon, name, description)
{
"fields" : {
"path" : { "type" : "text", "source" : "path" },
"public_key" : { "type" : "text", "source" : "public_key" },
"icon" : { "type" : "image", "source" : "icon" },
"name" : { "type" : "text", "source" : "name" },
"description" : { "type" : "text", "source" : "description" }
},
"parName" : "myapps",
"method" : 103,
"table" : "appslist",
"callBackID" : "25b4599a-eead-6f6c-894e-e4de05b1364b"
}
My object model
struct params: Decodable {
let fields: fields?
let parName: String?
let method: Int?
let table: String?
let callBackID: String?
}
struct fields: Decodable {
let name: properties?
let description: properties?
let public_key: properties?
let path: properties?
let icon: properties?
let imagelist: properties?
let templatepath: properties?
let thumbnail: properties?
}
struct properties: Decodable {
let source: String?
let type: String?
}
If you want a loop and the keys are dynamic decode the fields as [String:Properties]
First of all declare the structs with capitalized names and declare only those properties as optional which can be nil.
struct Params: Decodable {
let fields: [String:Properties]
let parName: String
let method: Int
let table: String
let callBackID: String
}
struct Properties: Decodable {
let source: String
let type: String
}
Then decode the JSON, define an array of key paths and enumerate the array (data is the Data instance representing the JSON)
do {
let result = try JSONDecoder().decode(Params.self, from: data)
let fields = result.fields
for (key, _) in result.fields {
print(key)
}
} catch {
print("error: ", error)
}