Swift Create Json for API REST - ios

I need create a json for send from a API REST:
{
"ownId": "seu_identificador_proprio",
"amount": {
"currency": "BRL",
"subtotals": {
"shipping": 1000
}
},
"items": [
{
"product": "Descrição do pedido",
"quantity": 1,
"detail": "Mais info...",
"price": 1000
}
],
"customer": {
"ownId": "seu_identificador_proprio_de_cliente",
"fullname": "Jose Silva",
"email": "nome#email.com",
"birthDate": "1988-12-30",
"taxDocument": {
"type": "CPF",
"number": "22222222222"
},
"phone": {
"countryCode": "55",
"areaCode": "11",
"number": "66778899"
},
"shippingAddress": {
"street": "Avenida Faria Lima",
"streetNumber": 2927,
"complement": 8,
"district": "Itaim",
"city": "Sao Paulo",
"state": "SP",
"country": "BRA",
"zipCode": "01234000"
}
}
}
I am confused with the creation..
I try begin with [NSObject:AnyObject]
var d1 : [NSObject:AnyObject] = ["ownId":"seu_identificador_proprio", "customer":""]
let dd1 = ["currency":"BRL"]
let dd2 = ["shipping":"1000"]
let arr = [d1]
let d = try! NSJSONSerialization.dataWithJSONObject(arr, options: NSJSONWritingOptions.PrettyPrinted)
let s = NSString(data: d, encoding: NSUTF8StringEncoding)! as String
print(s)
But I need help!

I have updated your code and added some hints, how can you build the above listed structure. Happy coding!
// Do not use NSObject as key's type
// Keys in a dictionary are usually Strig in every language
var d1: [String: AnyObject] = ["ownId":"seu_identificador_proprio", "customer":""]
// Define the type of your dictionaries, if you dont, in this case it will create a [String:String] dictionary, but you need to insert an array into it
// Make it a var, so you can mutate the container
var dd1: [String: AnyObject] = ["currency":"BRL"]
// Here the type is undefined. Try inserting anything else than String, and see the results
let dd2 = ["shipping":"1000"]
dd1["subtotals"] = dd2
d1["amount"] = dd1
// Build all your dictionaries like i did above, and at the end add all of them into arr
let arr = [d1]
// Do not force try any throwing function in swift - if there is an error, your application will crash
// Use proper error handling - https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html
do {
let d = try NSJSONSerialization.dataWithJSONObject(arr, options: NSJSONWritingOptions.PrettyPrinted)
let s = NSString(data: d, encoding: NSUTF8StringEncoding)! as String
print(s)
} catch {
// Do your error handling here
}

Related

Can't get the value from the JSON (Could not cast value of type '__NSCFNumber' (0x7fff87b9c520) to 'NSDictionary' (0x7fff87b9d5b0))

I'm just starting my way in programming, and I'm stuck with the problem of pulling parameters out of JSON.
Here is what a JSON file looks like:
{
"results": 1,
"data": [
{
"wind": {
"degrees": 220,
"speed_kts": 4,
"speed_mph": 5,
"speed_mps": 2
},
"temperature": {
"celsius": 13,
"fahrenheit": 55
},
"dewpoint": {
"celsius": 12,
"fahrenheit": 54
},
"humidity": {
"percent": 94
},
"barometer": {
"hg": 29.85,
"hpa": 1011,
"kpa": 101.09,
"mb": 1010.92
},
"visibility": {
"miles": "Greater than 6",
"miles_float": 6.21,
"meters": "10,000+",
"meters_float": 10000
},
"elevation": {
"feet": 98.43,
"meters": 30
},
"location": {
"coordinates": [
-6.06011,
36.744598
],
"type": "Point"
},
"icao": "LEJR",
"observed": "2019-12-01T18:00:00.000Z",
"raw_text": "LEJR 011800Z 22004KT 9999 FEW020 13/12 Q1011",
"station": {
"name": "Jerez"
},
"clouds": [
{
"code": "FEW",
"text": "Few",
"base_feet_agl": 2000,
"base_meters_agl": 609.6
}
],
"flight_category": "VFR",
"conditions": []
}
]
}
I want to retrieve the barometric pressure in hPa (results => data => barometer => hpa).
And here is my code (I use Alamofire):
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request("https://api.checkwx.com/metar/lejr/decoded", headers: headers).responseJSON { response in
// print(response)
if let metardataJSON = response.result.value {
let metarDataObject:Dictionary = metardataJSON as! Dictionary<String, Any>
print(metarDataObject)
let resultsObject:Dictionary = metarDataObject["results"] as! Dictionary<String, Any>
let dataObject:Dictionary = resultsObject["data"] as! Dictionary<String, Any>
let barometerObject:Dictionary = dataObject["barometer"] as! Dictionary<String, Any>
let hpaObject:NSNumber = barometerObject["hpa"] as! NSNumber
print(hpaObject)
}
}
After all the attempts, I cannot get rid of the error "Thread 1: signal SIGABRT":
Could not cast value of type '__NSCFNumber' (0x7fff87b9c520) to 'NSDictionary' (0x7fff87b9d5b0).
2019-12-01 19:34:18.723588+0100 Metar[6721:452116] Could not cast value of type '__NSCFNumber' (0x7fff87b9c520) to 'NSDictionary' (0x7fff87b9d5b0).
Can anyone shed some light on this issue and help me to improve my code?
Forgive me if the question seems simple or inappropriate - I'm just a beginner :)
Drop the first extraction line and refer to the metarDataObject in the second line. And note that inside "data" there is an array:
let dataObject:Dictionary = metarDataObject["data"] as! [[String: Any]]
let barometerObject:Dictionary = dataObject[0]["barometer"] as! [String: Any]
let hpaObject:NSNumber = barometerObject["hpa"] as! NSNumber
To not have to deal with these kinds of issues in the future I recommend to use some kind of "object mapping" framework which takes care of mapping the json into a useable, type-safe struct.

Adding to dictionary dynamically

I 'm having an array of dictionary like so...
[
{
"id" : "3",
"sellingPrice" : "520",
"quantity" : "15"
},
{
"id" : "5",
"sellingPrice" : "499",
"quantity" : "-1"
},
{
"id" : "8",
"sellingPrice" : "500",
"quantity" : "79"
}
]
Now I want to add to the dictionary another key called remaining_balance with a value of 420,499 & 500 respectively. How can I achieve this..? Hope somebody can help...
It seems like you want to add a value to your dictionary that is an array:
var arrDict = Array<Dictionary<String,Any>>() //Your array
arrDict.append(["id":"3","sellingPrice":"520","quantity":"13"])
arrDict.append(["id":"5","sellingPrice":"43","quantity":"32"])
arrDict.append(["id":"8","sellingPrice":"43","quantity":"33"])
let arrValue = ["420","499","500"] //Your remaining value in array
print("Before ",arrDict)
for (index,dict) in arrDict.enumerated() {
var dictCopy = dict //assign to var variable
dictCopy["remaining_balance"] = arrValue[index]
arrDict[index] = dictCopy //Replace at index with new dictionary
}
print("After ",arrDict)
EDIT
If you are able keep an index of an array it would be possible,
Assuming that you have the index of an array
var dictCopy = arrDict[index]
dictCopy["remaining_balance"] = "666" //Your calculated value
arrDict[index] = dictCopy //Replace at index with new dictionary
var newKV = [["remaining_balance": "420"],["remaining_balance": "490"],["remaining_balance": "500"]]
let array = [["id":"3", "sellingPrice":"520", "quantity":"15"], ["id":"5", "sellingPrice":"520", "quantity":"15"], ["id":"8", "sellingPrice":"520", "quantity":"15"]]
let newArray = array.enumerated().map { (index : Int, value: [String: String]) -> [String: String] in
var dic = value
dic.merge(newKV[index]) { (_, new) -> String in
new
}
return dic
}
You could achieve it by mapping your array:
var myArray = [["id": "3", "sellingPrice": "520", "quantity" : "15"], ["id": "5", "sellingPrice": "499", "quantity" : "-1"], ["id": "8", "sellingPrice": "500", "quantity" : "79"]]
print(myArray)
/*
[["id": "3", "sellingPrice": "520", "quantity": "15"],
["id": "5", "sellingPrice": "499", "quantity": "-1"],
["id": "8", "sellingPrice": "500", "quantity": "79"]]
*/
print("___________________")
var remainingBalanceDesriedValue = 420
myArray = myArray.map { (dict: [String: String]) -> [String: String] in
var copyDict = dict
copyDict["remaining_balance"] = "\(remainingBalanceDesriedValue)"
remainingBalanceDesriedValue = (remainingBalanceDesriedValue == 420) ? 499 : (remainingBalanceDesriedValue == 499) ? 500 : 420
return copyDict
}
print(myArray)
/*
[["sellingPrice": "520", "quantity": "15", "id": "3", "remaining_balance": "420"],
["sellingPrice": "499", "quantity": "-1", "id": "5", "remaining_balance": "499"],
["sellingPrice": "500", "quantity": "79", "id": "8", "remaining_balance": "500"]]
*/
Let's assume you have an array of dictionaries like so:
var arrayOfDictionaries = [
[
"id": 3,
"sellingPrice": 520,
"quantity": 15
]
]
It is important that arrayOfDictionaries is not a let constant, otherwise it is considered immutable and you can not call append on it.
Now you init a new dictionary like:
let newDictionary = [
"id": 10,
"remaining_balance": 420,
"quantity": 15
]
Now add the newDictionary like
arrayOfDictionaries.append(newDictionary)
If the order is important
If the order is important there are a couple of ways to go about that.
When calling append the new value (in this case the new dictionary) will always be inserted at the bottom of the array.
If for some reason you can not call append in the correct order you could use insert, which inserts your dictionary at a specific position.
Yet another way is to append the values wildly and after you are done, call sort on the array.
Improvement Tips
Notice that for the values I did not use strings, as you only have numbers like "id" : 30.
Also, if you want the second key to be called remaining_balance you should call the first key selling_price instead of sellingPrice. Because of conistency.
Alternative approach
As far as I have understood you are trying to implement some software that is responsibly for selling some products.
I think you are tackling this problem from a completely wrong side.
I think you should read about database relationships. Selling products actually is a very common problem.
Maybe this will help you. I would offer a possible solution myself, but I think this misses the point of your question.
If you decide to use the database approach, you won't necessarily have to use a database. You can take the approach and implement it using simple structs/classes/arrays.
I noticed this question lacks an extension answer, yes.. I'm gonna be that guy, so here it is. This could be made more generic by supporting other types of dictionaries, feel free to pitch in ;)
Inspiration from #eason's answer.
var newKV = [["remaining_balance": "420"],["remaining_balance": "490"],["remaining_balance": "500"]]
var array = [["id":"3", "sellingPrice":"520", "quantity":"15"], ["id":"5", "sellingPrice":"520", "quantity":"15"], ["id":"8", "sellingPrice":"520", "quantity":"15"]]
extension Array where Element == [String: String] {
enum UniquingKeysStrategy {
case old
case new
}
mutating func merge(with target: Array<Element>, uniquingKeysWith: UniquingKeysStrategy = .new) {
self = self.merged(with: target)
}
func merged(with target: Array<Element>, uniquingKeysWith strategy: UniquingKeysStrategy = .new) -> Array<Element> {
let base = self.count > target.count ? self : target
let data = self.count > target.count ? target : self
return data.enumerated().reduce(into: base, {
result, data in
result[data.offset]
.merge(data.element, uniquingKeysWith: {
old, new in
if strategy == .new { return new }
return old
})
})
}
}
let mergedArrays = newKV.merged(with: array, uniquingKeysWith: .old)
array.merge(with: newKV)
Happy Coding :)

Why SwiftyJSON cannot parse Array String in swift 3

{
"item": [
{
"pid": 89334,
"productsname": "Long Way",
"address": "B-4/7, Malikha Housing, Yadanar St., Bawa Myint Ward,",
"telephone": "[\"01570269\",\"01572271\"]"
},
{
"pid": 2,
"productsname": "Myanmar Reliance Energy Co., Ltd. (MRE)",
"address": "Bldg, 2, Rm# 5, 1st Flr., Hninsi St., ",
"telephone": "[\"202916\",\"09-73153580\"]"
}
],
"success": true
}
I cannot parse telephone value from above JSON object with following code.
for item in swiftyJsonVar["item"].array! {
if let jsonDict = item.dictionary {
let pid = jsonDict["pid"]!.stringValue
let productsname = jsonDict["productsname"]!.stringValue
var telephones = [String]()
for telephone in (jsonDict["telephone"]?.array)! {
telephones.append(telephone.stringValue)
}
}
}
I want to get and display one by one phone number of above JSON. I'm not sure why above code is not working. Please help me how to solve it, thanks.
Because telephone is a string that looks like an array, not an array itself. The server encoded this array terribly. You need to JSON-ify it again to loop through the list of telephone numbers:
for item in swiftyJsonVar["item"].array! {
if let jsonDict = item.dictionary {
let pid = jsonDict["pid"]!.stringValue
let productsname = jsonDict["productsname"]!.stringValue
var telephones = [String]()
let telephoneData = jsonDict["telephone"]!.stringValue.data(using: .utf8)!
let telephoneJSON = JSON(data: telephoneData)
for telephone in telephoneJSON.arrayValue {
telephones.append(telephone.stringValue)
}
}
}

Post JSON request in Swift 3

I need to post JSON data that looks like this :
{ “orders”:[ {“id”: 208, “quantity”: 1 },{“id”: 212, “quantity”: 2},{“id”: 202, “quantity”: 5}, ...etc ],“HHStatus”: “1 }
I have the following variable :
var orders : [ShoppingCart] = []
that contains data as :
[Crash.ShoppingCart(drinkId: 743, drinkName: "aqua", drinkPrice: "2.26", drinkQuantity: 2), Crash.ShoppingCart(drinkId: 715, drinkName: "yellow", drinkPrice: "6.92", drinkQuantity: 1), Crash.ShoppingCart(drinkId: 738, drinkName: "blue", drinkPrice: "4.69", drinkQuantity: 2)]
...etc
I am able to post the request using :
for order in orders {
let orderId = order.drinkId
let orderQuantity = order.drinkQuantity
let parameters = ["orders": [["id": orderId, "quantity": orderQuantity]], "HHStatus": orderHHStatus!] as [String : Any]
let jsonData = try! JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
but then I want the whole order not just one id and one quantity,
and I have tried using :
let orderId = orders.map { $0.drinkId }
let orderQuantity = orders.map { $0.drinkQuantity }
let parameters = ["orders": [["id": orderId, "quantity": orderQuantity]], "HHStatus": orderHHStatus!] as [String : Any]
let jsonData = try! JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
but then I end up with something like this :
["HHStatus": "0", "orders": [["id": [743, 715, 738], "quantity": [2, 1, 2]]]]
How can I send all the ids and quantities in one request?
I can't figure out how to get something like :
["orders": [["id": orderId, "quantity": orderQuantity],["id": orderId, "quantity": orderQuantity], ["id": orderId, "quantity": orderQuantity]], "HHStatus": orderHHStatus!]
so many thanks for any help provided!
Map the ShoppingCart array to an array of dictionaries with the map function:
let mappedOrders = orders.map { ["id" : $0.drinkId, "quantity" : $0.drinkQuantity] }
Create the parameters dictionary
let parameters : [String:Any] = ["orders" : mappedOrders, "HHStatus" : orderHHStatus!]
Don't pass the .prettyPrinted option, the server doesn't care about aesthetics.
Omit the options parameter.

Swift - Compare Dictionaries

I have two Dictionaries that look like:
var dict1 = [Int: [String: AnyObject]]
var dict2 = [Int: [String: AnyObject]]
for example:
dict1: [0: ["sender": "user1", "time": NSDate(), "mId": "as2f2ASf"], [1: ["sender": "user1", "time": NSDate(), "mId": "Sjf82FsJ"]
dict2: [0: ["sender": "user2", "time": NSDate(), "mId": "J2fAS92D"], [1: ["sender": "user2", "time": NSDate(), "mId": "Sjf82FsJ"]
I want to find out if the dictionaries have data with the same mId and if, I want to do some action.
I wrote this code for that and got these errors.
for (_, value) in dict1! {
for content in value {
if content.0 == "mId" {
var mID = content.1
for (_, 2ndValue) in dict2 {
for 2ndContent in 2ndValue {
if 2ndContent.0 == "mId" {
var 2ndMID = 2ndContent.1
if mID == 2ndMID {
//Do Some Action
}
}
}
}
}
}
}
Here are the errors:
https://www.dropbox.com/s/e28ple6640hkrzo/Bildschirmfoto%202015-08-28%20um%2021.21.54.png?dl=0
Firstly, as Eric says in his comment, you are getting errors because you can't start a variable name with a number.
Secondly what you are calling a 'dictionary' here is in fact an array of tuples - if you define your dict1 variable in the Swift REPL by running var dict1 = [Int,[String,AnyObject]()) you get:
dict1: [(Int, [String : AnyObject])] = 0 values
A dictionary with the equivalent structure would be defined thus:
var dict1 = [Int:[String:AnyObject]]() - this returns
dict2: [Int : [String : AnyObject]] = 0 key/value pairs
in the REPL.
Therefore the dict1 and dict2 declarations you show will not work. They need to be declared as follows to match the type you've specified:
var dict1 = [(0, ["sender": "user1", "time": NSDate(), "mId": "as2f2ASf"]), (1, ["sender": "user1", "time": NSDate(), "mId": "Sjf82FsJ"])]
var dict2 = [(0, ["sender": "user2", "time": NSDate(), "mId": "J2fAS92D"]), (1, ["sender": "user2", "time": NSDate(), "mId": "Sjf82FsJ"])]
If you want to use an actual dictionary, use :
var dict3 = [[0: ["sender": "user1", "time": NSDate(), "mId": "as2f2ASf"]], [1: ["sender": "user1", "time": NSDate(), "mId": "Sjf82FsJ"]]]
While I can see what you're trying to achieve in the code you've posted, I don't think the approach you're taking is the right one. Any time you have 4 levels of nested for loops you should consider whether there's a better way of solving the problem.
You are iterating over all the keys in the dictionary when you are only interested in the value of "mId". Just looking for the value of that key gets rid of 2 loops and a lot of pointless iterating over things you aren't interested in:
for (_,value1) in dict1 {
if let mld1 = value1["mId"] {
for(_,value2) in dict2 {
if let mld2 = value2["mId"] {
if mld1 == mld2 {
println("Found diff")
}
}
}
}
}
The if let is necessary to ensure you are making a valid comparison (i.e. to avoid a false positive if the value of 'mld' is nil in both dicts). No idea whether this is even possible in your data model but always worth being thorough. Note that this solution uses arrays of tuples, as in your examples - you'd need something slightly different if you use actual dictionaries.
Well im not sure i understood your problem, but this is my idea for that:
for (key, value) in dicOne {
for (keyTwo, valueTwo) in dicTwo {
for (keyItem,valueItem) in value {
for (keyItemTwo, valueItemTwo) in valueTwo {
if keyItem == keyItemTwo && valueItem == valueItemTwo{
println("do some action")
}
}
}
}
}
The first loop is for the first dictionary and the second, for the other dictionary. After this you'r in the second layer ["a": "A"] of both dictionaries. So the next step is to get this dictionary. For this are the other two loops.
Just a question: Did u tried tuple? Like this:
var dictionaryOne:[Int: (String, String)] = [1: ("a", "A")]
var dictionaryTwo:[Int: (String, String)] = [1: ("a", "A")]
for (key, value) in dictionaryOne {
for (keyTwo, valueTwo) in dictionaryTwo {
if value.0 == valueTwo.0 && value.1 == valueTwo.1 {
println("nice action")
}
}
}

Resources