Parsing an array in swift with null values (not nil) - ios

I'm calling webservice in swift for an iOS app, i have the webservice returns data in the form of array .. like this :
["354", "Air Conditioning", "null", "2", "Street EG", null, null, null, null, null, "50", "20", "2017-01-22T14:30:46Z", "27", "24", "18", "13", "0", null, null, null, null ] ..
the problem is that when it populates an array it suppresses the null values and reduces the length of the array which is not right, i need the data to be "null" if it is null or nil because i get values by index and each index is know to be null or with value but it must be there

Use optionals. Your array would be
var array = [String?]
With optionals, you can accept nil values.
When you append the value to the array, now it can accept nil

If you convert this JSON with something like JSONSerialization.jsonObject(with: data), the resulting array doesn't suppress the null entries. They're represented by NSNull objects. If your null entries are suppressed, then you should edit your question to share the code that is doing that. Standard JSON parsing routines will preserve these values without incident. For example, in Swift:
guard let jsonObject = try? JSONSerialization.jsonObject(with: data), let array = jsonObject as? [Any] else {
print("can't parse it")
return
}
for object in array {
if object is NSNull {
print("Hey, it's null!")
} else {
print("It's not null, it's \(object)")
}
}
You can see that the null values are preserved, represented with NSNull (except the first one, which because it's in quotes, is a string with four characters, "null").

Related

How to correctly send array with objects in JSON Swift iOS

Hello I am beginner and trying to understand how to send an array with objects. Does the server understand what an array is like Int, Strings or Booleans? Do you have to send the array in a string for JSON? What I do not understand?
var productsResult = ""
let encoder = JSONEncoder()
let productObject = ProductUsed(name: "Custom name", reason: "This Reason", apply_way: "Intravenous infusion", dosing: "2x", date_start: "22-02-1999", date_end: "22-03-2003")
do {
let result = try encoder.encode([productObject])
if let resultString = String(data: result, encoding: .utf8) {
print(resultString)
productsResult = resultString
}
} catch {
print(error)
}
json["products_used"] = productsResult
And I sent to server with parameters like this:
parameters: ["pregnancy_week": 0, "body_height": 198, "initials": "John Appleseed", "heavy_effect": false, "sex": "Male", "pregnancy": false, "month_of_birth": 3, "reaction": "No option checked", "additional_info": "Eeee", "products_used": "[{\"date_end\":\"22-03-2003\",\"dosing\":\"2x\",\"date_start\":\"22-02-1999\",\"apply_way\":\"Intravenous infusion\",\"name\":\"Custom name\",\"reason\":\"This Reason\"}]", "description": "Eeee", "result": "Recovery without lasting consequences", "year_of_birth": 1983, "day_of_birth": 11, "issue_date": "15-11-2020", "body_weight": 78]
but printed "resultString" in log and looks good...
[{"date_end":"22-03-2003","dosing":"2x","date_start":"22-02-1999","apply_way":"Intravenous infusion","name":"Custom name","reason":"This Reason"}]
What's wrong in my code and why I have " \ " between words in "products_used" key?
JSON, unlike XML, does not specify the structure and type explicitly. This means that the server must know what JSON data to expect.
In JSON there are a few value types (https://www.w3schools.com/js/js_json_syntax.asp):
a string
a number
an array
a boolean
null
a JSON object (a dictionary with tags like { "first" : "John", "last" : "Doe" }). This allows nesting.
A JSON object is a set of tag-value pairs. The tag and value are separated by : and pairs are separated by ,.
An array is a list of JSON values. So for example [ "hello", world" ] is a JSON array with 2 strings and [ 12, 54 ] is a JSON array with two numbers.
Your parameter list ["pregnancy_week": 0, "body_height": 198, ... is not an array but a dictionary instead. A Swift dictionary is translated to an JSON object, not a JSON array.
The \ you see printed acts as escape character. This escape character is used to allow you to have a " inside the string.
That's just a few things that I hope will help understand things a bit better. Your questions are pretty basic, which is fine and it's great you want to understand things. But instead of us explaining everything here, I think it would be best if you'd read about the structure of JSON and how JSON works in Swift on your own.

Parsing a nested JSON as a dictionary with Swift / SwiftyJSON

I'm using SwiftyJSON to parse a nested JSON. The JSON is used to populate a form where the user is shown the "keys" from the JSON to select from and then the corresponding values to the selection are used to calculate a score.
I've tried to parse the JSON and the parsing works well to get the rest of the data (e.g. the question) but when I try to parse the portion of the JSON where the scores (key: values) are, I get null.
{
"Question": "Pick a Number from the given values",
"Answer_Choices": {
"10": "6",
"9": "6",
"8": "3",
"7": "3",
"6": "1"
}
}
In the above code I want to display the left numbers to the user where they pick the 'keys' and correspondingly I will assign the values the values to contribute to the user's score, e.g. if the user selects 8, I'll assign them 3. I'm not sure how I can cast the key as well as values dynamically. They always fill up as null.
Question is parsed as:
var question = JSON["Question"].string
var answerChoices = JSON["Answer_Choices"].dictionaryObject // I know this is probably not correct.
You are pretty close. Here is how you can parse to get separate arrays for answers and points
guard let dict = json["Answer_Choices"].dictionaryObject as? [String:String] else {
return
}
let answerArray = Array(dict.keys)
let pointsArray = Array(dict.values)

DDMathParser: Parsing dynamic formula which contain $ to refer objects value within dictionary

I am struggling a little bit to use DDMathParser framework for expression requirement I have. I have JSON of fields & based on expressions certain fields can be set required, hidden or set the value of it.
Expressions in required tag in sample JSON are not fixed & so not getting how to achieve dynamic approach for expression.
[
{
"name": "firstName",
"value": "Ameer",
**"required": true**
},
{
"name": "lastName",
"value": "Shaikh",
**"required": "$firstName != ‘’"**
},
{
"name": "designation",
"value": "",
**"required": "$firstName == ‘Ameer’ && $lastName == ‘Shaikh’"**
},
{
"name": "location",
"value": "",
**"hidden": false**
}
]
Actually, expression in JSON contains $ to represent one of the
dictionary objects value from JSON. Wherein framework internally
treats it as a local variable.
These expressions may have different combinations as well. There may be several expression apart from "required" parameters. I need to run all relevant expressions for any change in value in UI.
EDIT
let expression = "$firstName == ‘Ameer’ && $lastName == ‘Shaikh’"
let dict = ["firstName": "Amir", "lastName": ""]
let e = try! Expression(string: expression)
let result = try! Evaluator.default.evaluate(e, substitutions: dict)
Though it should parse a correct value from JSON, I have hard coded substitutions string to at least get a breakthrough. Here, substitutions expect String & Double & give error as "Cannot convert a value of type [String: String] to expected arg type substitutions (Dcitionary).
Is there any way to pass String: String substitutions?
DDMathParser is not built to do string evaluations. It's technically possible to make it work, but it's a bit beyond the scope of the framework.
For this situation, I think you'd be better off using NSPredicate, which does allow string comparisons and variable substitutions.

Iterating through an array of dictionaries to get all the keys

I have an array of dictionaries [[String : AnyObject]] called rooms in a User object - each dictionary holds a name as the String and an id as the AnyObject.
I want to populate a table view with the names, so I'm trying to loop through the array and grab the String values from the dicts.
if let roomDict = myUser.rooms as? [[String : AnyObject]] {
for (roomNames, _) in roomDict {
cell.textLabel?.text = roomNames
}
}
I'm relatively new and from what I've seen in tutorials and such when looping through dictionaries, you use the underscore to specify that you don't want the second value. So just grab all the first values (in this case, the names), and set them to the roomNames variable.
However I'm confused here because I'm not looping through a dictionary, I'm looping through an array of dictionaries. So I'm not sure how to do that. I did a search and the results I saw generally were asking about JSON, which isn't the case here. How can I do this?
Thanks for any help!
Firstly, your dictionary structure isn't ideal. Rather than having the key as the room name and the value as the identifier, your dictionary should have known key names, with variable values. Keys should not be "data" in a dictionary.
So, rather than
["room1":1]
it would be better if it were
["roomName":"room1", "roomID":1]
with your current structure, however, assuming that there is only one key per dictionary and that is the room name, you can get the names with:
if let rooms = myUser.rooms as? [[String : AnyObject]] {
roomNames = rooms.map({ $0.keys.first!})
}
If you use the better structure I suggested then it would be
if let rooms = myUser.rooms as? [[String : AnyObject]] {
roomNames = rooms.map({ $0["roomName"] as? String ?? ""})
}
I'm not clear about your data structure. If you have an array of dictionaries, and you want all the keys, you could use code like this:
let array = [
["key1": "value1",
"key2": "value2",
"key3": "value3",
"key4": "value4"],
["key5": "value5",
"key6": "value6",
"key7": "value7",
"key8": "value8"],
["key9": "value9",
"key10": "value10",
"key11": "value11",
"key12": "value12"]
]
let keys = array
.map{$0.keys}
.reduce([], +)
print(keys)
That will give you an array of all the keys from all the dictionaries. The keys from each dictionary will be in a jumbled order however, since dictionaries are unordered. You'll get the keys from each inner dictionary in a jumbled order, followed by the keys from the next dictionary in the array, etc.
Sample output:
["key2", "key3", "key4", "key1", "key7", "key8", "key5", "key6", "key9", "key10", "key12", "key11"]
If you want to sort the keys, you can do that:
let keys = array
.map{$0.keys}
.reduce([], +)
.sorted{$0.compare($1, options: .numeric) == .orderedAscending}
(In the above code I'm using the String class's compare(_:options:) function with an options value of .numeric so that "key11" sorts after "key10" instead of ["key1", "key11", "key12", "key2"], which you get from standard string ordering.)
The output of the sorted version (with the .numeric option) is:
["key1", "key2", "key3", "key4", "key5", "key6", "key7", "key8", "key9", "key10", "key11", "key12"]
Without the .numeric option, the output would be:
["key1", "key10", "key11", "key12", "key2", "key3", "key4", "key5", "key6", "key7", "key8", "key9"]
If your keys contain mixed upper/lower case and you want to ignore it, you'd use options of [.numeric, .caseInsensitive] (case insensitive sorting where numbers within strings are compared using numeric value.)

Dictionary Contain NSNull Swift

Is there any way to detect that an NSDictionary contains a NSNull value?
Be careful when you put NSDictionary and Swift in the same sentence. NSDictionary is a Foundation (i.e. Objective-C) reference type. Swift has its own native Dictionary, which is a value type (i.e. struct). You can bridge between the two easily, but it takes some CPU time doing so.
Now on to your question:
let dict: [String: Any] = [
"firstName": "John",
"lastName": "Smith",
"age": NSNull()
]
let containsNSNull = dict.contains { $0.1 is NSNull } // true

Resources