How to store array of dictionaries into class variable? - arrays

I have an array of dictionaries that is being read in from a JSON file as seen below. I would like to store that value (jsonResult) into a class variable so that I can use it to populate a tableview. However, I don't quite understand how to store that value.
Here is how I am getting my array of dictionaries (jsonResult):
if let path = Bundle.main.path(forResource: filename, ofType: "json") {
do {
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves) as! [String:Any]
self.tableData = jsonResult // WHAT GOES HERE?
} catch {
// handle error
}
}
And this is my class variable that I want to store my array of dictionaries into:
var tableData = [Dictionary<String, String>]()
How can I correctly store jsonResult into tableData? I do not want to use a struct as the structure of the dictionaries can vary.

You state the JSON is an array of dictionary but you are casting the result of JSONSerialization.jsonObject to just a dictionary. Since you seem to be expected an array of dictionary with both string keys and values, cast the result accordingly. But do it safely. Never use ! when working with JSON.
if let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves) as? [[String:String]] {
self.tableData = jsonResult
} else {
// Error - unexpected JSON result
}
This assumes you want the top level of the JSON result. If in fact jsonResult should be a dictionary and that top-level dictionary has a key to the actual array of dictionary you want then you need to fix the code accordingly.

Related

How to save 2d array data permanently using userdefaults.standard

I'm trying to save 2d array data using userdefaults, but i'm getting this error Cannot convert value of type '[[String]]' to expected argument type 'String' here is my code
var tempQuestion2 = [tempQuestion]
if var tempData = UserDefaults.standard.stringArray(forKey: "tempData")
{
tempData.append(tempQuestion2)
tempQuestion2 = tempData
}
UserDefaults.standard.set(tempQuestion2, forKey: "tempData")
tempQuestion is a string array with data like [“9+1=10”, “5+4=9”] and i want tempQuestion2 to be [["9+1=10, "5+4=9"], ["3+4=7", "4+1=5"]] I'm guessing my issue is at UserDefaults.standard.stringArray. My question is different from the link because that question is about dictionary not array of array.
There's no problem saving and loading arrays of arrays to UserDefaults, to save your data use:
UserDefaults.standard.set(tempQuestion2, forKey: "tempData")
To read back (and update) the array of arrays use:
// Assuming tempQuestion is [String]
if var tempData = UserDefaults.standard.array(forKey: "tempData") as? [[String]] {
tempData.append(tempQuestion2)
UserDefaults.standard.set(tempData, forKey: "temp")
}

Swift3 how do I get the value of a specific key in a string?

I've got a server response returning
(
{
agreementId = "token.virtual.4321";
city = AMSTERDAM;
displayCommonName = "bunch-of-alphanumeric";
displaySoftwareVersion = "qb2/ene/2.7.14";
houseNumber = 22;
postalCode = zip;
street = "";
}
)
how do I get the value of agreementId? response['agreementId'] is not working. i've tried some example code with .first but I cannot get it working.
Some extra information, I do a http call to a server with alamofire. I try to parse the json to a constant response:
let response = JSON as! NSDictionary
However that returns a error message
Could not cast value of type '__NSSingleObjectArrayI' (0x1083600) to 'NSDictionary' (0x108386c).
So now parse the json to an array, which seems to be working. The code above is what
let response = JSON as! NSArry
print(response)
spits out.
Now I only need to retrieve the value from the key "agreementId" and I have no clue how to do that.
In swift you need to use Swift's native type Array/[] and Dictionary/[:] instead of NSArray and NSDictionary, if you specify the type like above means more specific then the compiler won't complain. Also use optional wrapping with if let or guard let to prevent crash.
if let array = JSON as? [[String:Any]] {//Swift type array of dictionary
if let dic = array.first {
let agreementId = dic["agreementId"] as? String ?? "N/A"//Set default value instead N/A
print(agreementId)
//access the other key-value same way
}
}
Note: If you having more than one object in your array then you need to simply loop through the array to access each dictionary of array.
if let array = JSON as? [[String:Any]] {//Swift type array of dictionary
for dic in array {
let agreementId = dic["agreementId"] as? String ?? "N/A"//Set default value instead N/A
print(agreementId)
//access the other key-value same way
}
}

How to save response.result.value from Alamofire in local array swift 3

Alamofire.request(NEWS_FEED_URL).responseJSON { response in
guard let newsResponse = response.result.value else{
print("Error: \(response.result.error)")
return
}
print("JSON: \(newsResponse)")
let localArray:Array = [newsResponse]
print("Local Array:", localArray)
}
I am using alamofire to fetch data from server and trying to write parser on the response data. When I fetch response.result.value from alamofire and print it is working fine. But as soon as I put response.result.value in my local array it gives
[<__NSArrayI 0x6080000bcf80>(
{
category = World;
})]
and so on as result (Console). Also I am unable to convert response value of type 'Any' to 'Array'. Please help me how to add response.result.value in local array of type 'Array'. Can someone explain something about type casting on alamofire in brief?
You need to simply cast the result of response.result.value to Array of Dictionary.
guard let newsResponse = response.result.value as? [[String:String]] else{
print("Error: \(response.result.error)")
return
}
print("JSON: \(newsResponse)")
let localArray = newsResponse
//Access the localArray
print("Local Array:", localArray)
//Now to get the desired value from dictionary try like this way.
let dic = localArray[0]
let title = dic["title"] ?? "Default Title"
let link = dic["link"] as? "Default link"
//... get other value same way.
Note : Your response is already an Array so don't make array from it by adding it inside another array.
There is problem in responseJOSN result because result may not correct JSON format to correct use [[String:Any]] for formating JSON
Alamofire.request(NEWS_FEED_URL).responseJSON { response in
guard let newsResponse = response.result.value as? [[String:Any]] else{
print("Error: \(response.result.error)")
return
}
print("JSON: \(newsResponse)")
let firstRow = newResponse[0]
let categoryValue = firstRow["category"] ?? "Default Category"
}
If you are using Decodable technique you can save the DATA from response in user defaults. User defaults allows us to save the DATA. When you need it you can just use JSON decoder to decode the JSON Data.

cast dictionary elements of different types

I am using such code to get JSON from server:
var jsonresult = NSArray()
do {
jsonresult = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSArray
}
It helps me to get an array of dictionaries in jsonresult variable.
Then I am looping through array to add all dictionaries to another array.
for i in jsonresult {
print(i)
self.otherArray.append(i as! Dictionary<String, AnyObject>)
}
I am using Dictionary type because there are strings values as well as Double values.
Problem is that after data is inserted I can not use "double" values. I get such error: Could not cast value of type 'NSTaggedPointerString' (0x10c472860) to 'NSNumber'
Yes, I know that I can use (value as! NSString).doubleValue but it would be better to cast NSTaggedPointerString into NSNumber in the begining.
Any ideas how can I do it? Maybe I can cast each element of dictionary while adding them to self.otherArray?

Generating a JSON-Array and converting it to a Base64-String

I'm trying to create a Base64-String in Swift. I have an example of a Base64-encoded string and its array-counterpart. My problem now is, that I don't know how I get an equivalent array to the one which is given in the example.
Because I didn't want to mess around in my XCode-project I did the following in a playground.
given array:
{"WHERE":{"Class":"%3f","Location":"3b"},"ORDER":["Day ASC","Location DESC"]}
given Base64-string:
eyJXSEVSRSI6eyJDbGFzcyI6IiUzZiIsIkxvY2F0aW9uIjoiM2IifSwiT1JERVIiOlsiRGF5IEFTQyIsIkxvY2F0aW9uIERFU0MiXX0=
First I'm decoding the example-string
let str = "eyJXSEVSRSI6eyJDbGFzcyI6IiUzZiIsIkxvY2F0aW9uIjoiM2IifSwiT1JERVIiOlsiRGF5IEFTQyIsIkxvY2F0aW9uIERFU0MiXX0="
let data = NSData(base64EncodedString: str, options: NSDataBase64DecodingOptions(rawValue: 0))
do {
let result = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
} catch let error {
print(error)
}
//"result" is ["WHERE": ["Class": "%3f", "Location": "3b"], "ORDER": ["Day ASC", "Location DESC"]]
Below I'm trying to reproduce the string from above
var array = [String : AnyObject]()
var arrayPartA = [String : String]()
arrayPartA["Class"] = "%3f"
arrayPartA["Location"] = "3b"
array["ORDER"] = ["Day ASC", "Location DESC"]
array["WHERE"] = arrayPartA
array //The playground says that "array" is ["ORDER": ["Day ASC", "Location DESC"], "WHERE": ["Class": "%3f", "Location": "3b"]]
//"ORDER" and "WHERE" are switched but I don't get them to be at the right position
let utf8str2: NSData = String(array).dataUsingEncoding(NSUTF8StringEncoding)!
let encodedStr = utf8str2.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
//Here "encodedStr" is WyJPUkRFUiI6ICgKICAgICJEYXkgQVNDIiwKICAgICJMb2NhdGlvbiBERVNDIgopLCAiV0hFUkUiOiB7CiAgICBDbGFzcyA9ICIlM2YiOwogICAgTG9jYXRpb24gPSAzYjsKfV0=
//but it should be eyJXSEVSRSI6eyJDbGFzcyI6IiUzZiIsIkxvY2F0aW9uIjoiM2IifSwiT1JERVIiOlsiRGF5IEFTQyIsIkxvY2F0aW9uIERFU0MiXX0=
I would be glad if someone could explain to me what I'm doing wrong and how I can reproduce the given Base64-string.
Since I'm new to this website I apologize in advance for wrong layout or other possible conventions I don't know.
Could you try this please? Is this what you wanted to do? It should convert a Dictionary to base64 String
func jsonToBaseString (yourJSON: [String: String]) -> String? {
do {
let jsonData = try JSONSerialization.data(withJSONObject: yourJSON, options: JSONSerialization.WritingOptions.prettyPrinted)
return
jsonData.base64EncodedString(options: .endLineWithCarriageReturn)
} catch {
return nil
}
}
Dictionary is Swifts JSON representation...
Two important things to understand:
What you are calling an array is not an array, it's a JSON dictionary (containing an array for the ORDER key).
Be careful not to confuse the syntax of arrays and dictionaries between Swift and JSON.
In Swift, an array: [0, 1], a dictionary: ["a":0, "b":1].
In JSON, an array: [0, 1], a dictionary: {"a":0, "b":1}.
A Swift dictionary is an unordered collection. There's no "position" for key-value pairs.
You'll need to change several things:
Your input string (not serialized) is not an array, but a JSON object.
Try constructing your string with a proper JSON library, such as SwiftyJSON.
String(array) is not enough to consistently convert your objects to strings. You should use a JSON serializer (such as SwiftyJSON json.rawString()).
let follow recommendation to use some json serialization, but take in account that
{
"alfa": 1,
"beta": true
}
and
{"beta":true,"alfa":1}
represents in JSON notation the same object even though their string representation ( doesn't matter if base64 encoded or not ) are different.

Resources