Create specific Json in Swift 4 - ios

I have to deliver some specific JSON to a webserver, but I'm very confused about how to use the correct arrays and dictionaries, so I can't get to my final result. I'm starting from this:
["entries": [
"member" : [
"id" : key,
"name" : value
],
"timestamp" : "\(dateString)"
]
]
in the JSON file I have to send to the server I can only have 1 "entries" and several "member" with specific "id" and "name" and timestamp. I'm aware that I have to use dictionaries but can't get to this result. This is what I tried so fare:
var leden = [Int: String]()
var jsonDict = [String: Any]()
var dateString = Date()
for (key, value) in leden{
jsonDict["\(key)"] = ["member" : [
"id" : key,
"naam" : value
],
"timestamp" : "\(dateString)"
]
}
jsonFinaal = ["entries": jsonDict]
this is as close as I could get, but good enough because the key in jsonDict should not be there, I added the "entries" in a second dictionary to make this a unique entry.
Anyone who can do beter to help me to the solution?

The value for members is an array of dictionaries, not a dictionary
This creates the structure sorted by the id keys
let leden = [1 : "Foo", 2: "Bar"]
let sortedKeys = leden.keys.sorted()
let dateString = Date()
var members = [[String:Any]]()
for key in sortedKeys {
let naam = leden[key]!
members.append(["member" : ["id" : key, "naam" : naam], "timestamp" : "\(dateString)"])
}
let entries = ["entries": members]
print(entries)
And the JSON string with
do {
let jsonData = try JSONSerialization.data(withJSONObject: entries)
let json = String(data: jsonData, encoding: .utf8)
print(json)
} catch { print(error) }

Related

Extract a word from a string using swift

i want to extract a word from a string something like this:
"{"photo" : "95.png",
"other_name" : "othername",
"name" : "Painting",
"services" : [],
"_id" : "id"}"
no i want to extract the value of name: from here how do i do that,
so it would be like any text the comes after "name" : " is the word i am looking for
i tried something like this
let index = onlyName.index(onlyName.index(of: "\"name\"") ?? onlyName.startIndex, offsetBy: 10)
let mySubstring = onlyName[..<index]
based on this question but onlyName.index(of: "\"name\"") is giving me null
i know i could just convert it to a json that will be easier but needs to be a string
so how can i get the value of the name,it could be using regx
"{"photo" : "95.png",
"other_name" : "othername",
"name" : "Painting",
"services" : [],
"_id" : "id"}"
The above is not the valid Json string, if it would be the valid Json string like the one below:
"{\"photo\" : \"95.png\",
\"other_name\" : \"othername\",
\"name\" : \"Painting\",
\"services\" : [],
\"_id\" : \"id\"}"
And if you can have valid Json string then you can easily get the value of any of the key i.e.
func dictionaryFromJsonString(_ json: String) -> [String: Any]? {
if let data = json.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
} catch {
print(error.localizedDescription)
}
}
return nil
}
And you can use it as
let jsonString = "{\"photo\" : \"95.png\",
\"other_name\" : \"othername\",
\"name\" : \"Painting\",
\"services\" : [],
\"_id\" : \"id\"}"
if let dictionary = dictionaryFromJsonString(jsonString) {
print(dictionary["name"])
}
As some people above suggested, that string is probably json, and you have reference to it somewhere in code. In that case, you could simply convert it to data, decode it, and access name:
struct MyStruct: Codable {
let name: String
}
let string = "{\"photo\" : \"95.png\", \"other_name\" : \"othername\", \"name\" : \"Painting\", \"services\" : [], \"_id\" : \"id\"}"
if let data = string.data(using: .utf8),
let parsed = try? JSONDecoder().decode(MyStruct.self, from: data) {
print(parsed.name)
}

how to append an array of dictionaries to another array

I tried to append an array of dictionaries which are coming from server to a globally declared array.but i am getting an error like "Cannot convert value of type '[Any]' to expected argument type '[String : Any]'"if anyone helps me would be great.Thanks in advance
var pro = [[String:Any]]()
var productsdetails = Array<Any>()
productsdetails = userdata.value(forKey: "products") as! Array
print("response\(productsdetails)")
self.pro = self.pro.append(productsdetails)
print(self.pro)
Use this code like below, i hope this works
var pro = [[String:Any]]()
if let productsdetails = userdata.value(forKey: "products") as? [[String:Any]] {
print("response\(productsdetails)")
self.pro.append(productsdetails)
print(self.pro)
}
to solve this iterate
var pro = [[String:Any]]()
if let productsdetails = userdata.value(forKey: "products") as? [[String: Any]] {
for details in productsdetails {
pro.append(details)
}
}
or you may use directly self.pro = productsdetails if you not to want iterate
**image shows [String : String] as I have used [String : String] instead of [String : Any]*
You can try this: (Swift-4.2)
var data: [String: Any] = [
"key1": "example value 1",
"key2": "example value 2",
"items": []
]
for index in 1...3 {
let item: [String: Any] = [
"key": "new value"
]
// get existing items, or create new array if doesn't exist
var existingItems = data["items"] as? [[String: Any]] ?? [[String: Any]]()
// append the item
existingItems.append(item)
// replace back into `data`
data["items"] = existingItems
}
Answer same as: Append to array in [String: Any] dictionary structure
Can you show us your response which has key products? As there is mismatch with the variable pro and productdetails. As i see pro holds values as "Array of Dictionary with key as String type and Value as Any type" which again has Array above it and productdetails is expecting Array of Any type not the Array of Dictionary Type. Assuming your products has Array of String Type or can be even a class object type you can do it as below.
var pro = Array<Any>() //Or You can make Array<String>() or Array<CustomClass>()
var userdata:[String:[String]] = ["products":["One","Two","Three"]]
var productsdetails = Array<Any>()
productsdetails = userdata["products"] ?? []
print("response\(productsdetails)")
pro.append(productsdetails)

Add json objects to array

On click of a submit button the data in my textfields and some other data are being converted to a json object like so…
let categoryName = self.categoryTextField.text
let categoryId = self.categoryID
let category_json: [String: [String:Any]] = [
"categoryDetails": [
"category_name": categoryName,
"category_id": categoryId
]
]
if let data = try? JSONSerialization.data(withJSONObject: category_json, options: .prettyPrinted),
let str = String(data: data, encoding: .utf8) {
print(str) // `str` gives the json object
self.categoryStrToPass = str
}
Now self.categoryStrToPass is assigned to another json object and then finally added to a string array like so…
let productID = self.prodID
let sellingPrice = self.mrpTextField.text
let categoryJSON = self.categoryStrToPass
let jsonObject: [String: [String:Any]] = [
"prodDetails": [
"product_id": productID,
"selling_price": sellingPrice,
“category_json”: categoryJSON
]
]
if let data = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted),
let str = String(data: data, encoding: .utf8) {
print(str)
self.jsonStrToPass = str
self.jsonStringArray.append(self.jsonStrToPass)
}
Now I’m storing jsonStringArray to coredata like so…
_product?.setValue(self.jsonStringArray, forKey:
"productJsonArray") // productJsonArray is an attribute of type Transformable and Custom class type Array<String>
And it is being fetched like so...
if let jsonObjArr = result.value(forKey: "productJsonArray") as?
Array<NSString> {
print(jsonObjArr)
}
Now on 2 different instances I have submitted the data which means on printing jsonObjArr while fetching,it should have 2 different json objects in one array like so..
[{
"prodDetails" : {
"product_id" : "0",
"category_json" : "{\n \"categoryDetails\" : {\n \"category_id\" : \"0\",\n \"category_name\" : \"prodCAT\"\n }\n}",
"selling_price" : "500",
}
}
{
"prodDetails" : {
"product_id" : "1",
"category_json" : "{\n \"categoryDetails\" : {\n \"category_id\" : \"0\",\n \"category_name\" : \"CATNEW\"\n }\n}",
"selling_price" : "1000",
}
}]
But instead, printing jsonObjArr is giving this…in 2 different arrays like so...
[{
"prodDetails" : {
"product_id" : "0",
"category_json" : "{\n \"categoryDetails\" : {\n \"category_id\" : \"0\",\n \"category_name\" : \"prodCAT\"\n }\n}",
"selling_price" : "500",
}
}]
[{
"prodDetails" : {
"product_id" : "1",
"category_json" : "{\n \"categoryDetails\" : {\n \"category_id\" : \"0\",\n \"category_name\" : \"CATNEW\"\n }\n}",
"selling_price" : "1000",
}
}]
How can I get multiple json objects in one single array...?
you can add objects of type [String: Any] to array like so
let firstCategoryName = "first"
let firstCategoryId = 1
let firstCategory = [
"category_name": firstCategoryName,
"category_id": firstCategoryId
] as [String : Any]
let secondCategoryName = "second"
let secondCategoryId = 2
var category_json = [[String:Any]]()
category_json.append(firstCategory)
let secondCategory = [
"category_name": secondCategoryName,
"category_id": secondCategoryId
] as [String : Any]
category_json.append(secondCategory)
print(category_json)
then serialize the array
Swift 4.0:
let firstObj = ["prodDetails": [
"product_id": 5,
"selling_price": 6,
]]
let secondObj = ["prodDetails1": [
"product_id1": 5,
"selling_price1": 6,
]]
let jsonObject = jsonStringArray.addingObjects(from: [firstObj,secondObj])
if let data = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted),
let str = String(data: data, encoding: .utf8) {
print(str) //prints array of dictionaries
}
category_json and jsonObject are of the same kind.
What you need to understand:
(NS)String <== String(data:encoding) or data(encoding:) ==> (NS)Data
Applied to specific String/Data: JSON:
JSON Stringified <== String(data:encoding) or data(encoding:) ==> JSON Data
Swift Array/ Swift (and the rest JSON compliant) <== (NS)JSONSerialization.jsonObject(withData:, options:) or (NS)JSONSerialization.data(withJSONObject:, options:) ==> JSON Data
You can't append like that the two JSON Stringified, you need to have an array at least at top level.
So, let's connect the dots, in pseudo code (not sure at all that the method name are error free)
let currentData = self.jsonStrToPass.data(encoding: .utf8)
let current = JSONSerialization.jsonObject(with:currentData, options:[]) as [String:[String:Any]]
let finalArray : [[String:[String:Any]]]()
finalArray.append(current)
finalArray.append(jsonObject)
let finalData = JSONSerialization.data(withJSONObject:finalArray, options:[])
let finalString = String(data:finalData, encoding:.utf8)
That's for the logic. I didn't do the if let, try/catch, etc.
I'd think it might be better to pass Any (for Swift Array/Dictionary instead of String) between your data to pass. It might be simpler to edit them (append, etc.) instead of String.

iOS swift json PUT request string array in parameters

I'm working with Alamofire and SwiftyJSON.
I'm trying to make a request with the following structure
{
"email":"ppp#ppp.com",
"password":"pppppp",
"categories": [
{"id":"2"},
{"id":"1"},
{"id":"6"},
{"id":"5"}
]
}
I'm using :
let parameters = [
"email" : userEmail,
"categories" : userPassword,
"categorias" : selectedCategoriesArray]
//where selectedCategoriesArray is a [[String]]()
I fill my selectedCategoriesArray in a loop with this line modifying the array:
selectedCategoriesArray.append(["id", "2"]) //where 2 can be any other number
Alamofire.request( .PUT, url, parameters)
It seems it's working fine but it isn't, I don't know if my String array is taking the right format to be sent to the WS or do I need to encode it in a special way?
Has anyone worked with something like this, A little help would be appreciate.
Thanks!
I think your array should have a type of [[String: String]] in this case.
let userEmail = "myemail#email.com"
let userPassword = "123456"
var selectedCategoriesArray: [[String: String]] = []
for i in 0...5 {
selectedCategoriesArray.append(["id": String(i)])
}
let parameters = [
"email" : userEmail,
"password" : userPassword,
"categories" : selectedCategoriesArray
]
Check with below
let savedData = ["id": 1, "id": 2]
let jsonObject: [String: AnyObject] = [
"email": “xyz#yopmail.com”,
"password": 123456,
"categories": savedData
]
let valid = NSJSONSerialization.isValidJSONObject(jsonObject) // true

Appending Multidimensional Dictionary

I have a multidimensional dictionary and I am trying to add data into it without deleting data, but overwrite if duplicate.
var items = [Int: AnyObject]()
var IdsAndDetails = [String:AnyObject]()
let index = 3 // static for test
...
for result in results {
// result is String (result also indicates itemId)
let details = self.IdsAndDetails[result]
// details is AnyObject like [String:String]
if let itemDetails = details {
// Here I want to append data into 'items' variable
// This doesn't work: (Error-1)
self.items[index]![result] = itemDetails
}
(Error-1):
Cannot assign to immutable expression to type AnyObject.
However, if I try like, it works but it's not the approach I want. It's re-creating the dictionary. Instead, I want to append the data.
self.items = [
index : [result : itemDetails]
]
The structure of dictionary I want to get in the end is:
items = [
index : [
"id1" : ["key": "value", "key": "value"],
"id2" : ["key": "val", "key": "val"],
],
index : [
"id3" : ["key": "val", "key": "val"],
"id4" : ["key": "val", "key": "val"],
"id5" : ["key": "val", "key": "val"],
]
]
// index is Integer
// [Key:Value] is [String:String] - itemDetails equal to all `[key:value]`s
// 'id' is also String
Update: I also tried, but no luck
let a = self.items[index]
a![result]! = itemDetails as [String:String]
Update 2:
let valueDict = (value as! NSDictionary) as Dictionary
for (key, val) in valueDict {
let keyString = key as! String
let valString = val as! String
self.items[index]![result]![keyString]! = valString
}
But it's throwing error:
fatal error: unexpectedly found nil while unwrapping an Optional value
But Surprisingly debugging shows all values:
po index : 1
po itemId : "123123"
po keyString: "keyInString"
po valString: "valInString"
Update 3:
for index in 1...5 {
var results = [String]()
// First I retrieve nearby users and assign it to key
let itemsRef = Firebase(url: self.secret + "/items")
eventsRef.queryOrderedByChild("user_id").queryEqualToValue(key).observeEventType(.ChildAdded, withBlock: { snapshot in
// ^ above 'key' is the user_id retrieved before
let itemDetails = snapshot.value // item details - [key:val, key:val]
let itemId = snapshot.key // item ids [id1,id2,id3]
// I used 'KeyAndDetails' to store all values with ids
let IdsAndDetails = [itemId: itemDetails]
self.itemIdsArray = []
self.itemIdsArray.append(itemId)
if index == 1 {
// self.items = [
// index : [itemId : itemDetails]
// ]
// ^ This worked and gave me the structure
// but I don't want to overwrite it, instead, I want to append
// on the dictionary
// This is where I am trying to append into `self.items`,
// and throws error:
self.items[index]?[result] = (eventDetails as! [String : String])
}
...
It seems like you're trying to bypass Swift's type system instead of working with it. Instead of using AnyObject, you should be trying to use the exact type you want for the value of that dictionary. In this case it looks like you want something like [Int: [String: [String: String]]] (although, like #EricD said in the comments, you should probably be using a struct instead, if at all possible).
Here's a quick (static) example similar to the code in your question:
var items = [Int: [String: [String: String]]]()
let idsAndDetails = ["id2": ["key3": "value3"]]
let index = 3
items[index] = ["id1": ["key1": "value1", "key2": "value2"]]
let result = "id2"
if let itemDetails = idsAndDetails[result] {
items[index]?[result] = itemDetails
}
At the end of that, items will be:
[3: ["id1": ["key1": "value1", "key2": "value2"], "id2": ["key3": "value3"]]]
The ? in items[index]?[result] tells Swift to make sure items[index] is non-nil before attempting to execute the subscript method. That way, if you try to update an index that doesn't exist in items you don't cause a crash.

Resources