I am working on JSON parsing in Swift.
var results = [String:[AnyObject]]()
The above results is having the data as shown below,
"fruit" = (
"apple",
"orange"
);
Here, data is appended dynamically during runtime. All I need is to get the keys and display them in table view as header.
How to get thekey from results in swift?
NSJSONSerialization code example...
var results = [String:[AnyObject]]()
let jsonResult = try NSJSONSerialization.JSONObjectWithData(results, options:NSJSONReadingOptions.MutableContainers);
for (key, value) in jsonResult {
print("key \(key) value2 \(value)")
}
You can convert JSON to dictionary as mentioned in the above link proposed by Birendra. Then suppose jsonDict is your json parsed dictionary. Then you can get collection of all keys using jsonDict.keys.
You need to use NSJSONSerialization class to convert in json format (eg. to convert in dictionary) and then get all keys from it.
I have used,
var results = [String:Array<DataModel>]
where,
class DataModel {
var name: String?
}
and to fetch the keys and value,
for i in 0...(results.length-1){
// To print the results keys
print(results.keys[results.startIndex.advancedBy(i)])
// To get value from that key
let valueFromKeyCount = (results[results.keys[results.startIndex.advancedBy(i)]] as Array<DataModel>).count
for j in 0...(valueFromKeyCount-1) {
let dm = results[results.keys[results.startIndex.advancedBy(i)]][j] as DataModel
print(dm.name)
}
}
Tested with Swift 4.2 to get first key or list of keys:
This "one-liner" will return the first key, or only key if there is only one.
let firstKey: String = (
try! JSONSerialization.jsonObject(
with: data,
options: .mutableContainers
) as! [String: Any]).first!.key
This one will get a list of all the keys as and array of Strings.
let keys: [String] = [String] ((
try! JSONSerialization.jsonObject(
with: data,
options: .mutableContainers
) as! [String: Any]).keys)
Both of the above examples work with a JSON object as follows
let data = """
{
"fruit" : ["apple","orange"],
"furnature" : ["bench","chair"]
}
""".data(using: .utf8)!
Related
Hello I have a json the returns me some parameters as variables.
It has Parameter1, Parameter2, Parameter3 etc..
I don't know how many parameters will it give me. It's not a list it's just different variables in the json.
Which is the best way to map a json like that? I use Object Mapper
For Example:
First Time the json is
{
"MyObject": {
"Parameter1": "p1",
"Parameter2": "p2",
"Parameter3": "p3",
"Parameter4": "p4"
}
}
And a second time the json is
{
"MyObject": {
"Parameter1": "p1",
"Parameter2": "p2",
"Parameter3": "p3"
}
}
You can try this.
let keyvalue = parentDict.value(forKey: "MyObject") as! NSDictionary
var lastValue = Keyvalue.allValues
var lastKey = Keyvalue.allKeys
for Keyname in Keyvalue.allKeys
{
print("Keyname %#",Keyname)
print("Value %#",Keyvalue.value(forKey:Keyname))
}
the first step to parse any JSON to make it reusable is to create your Model class or struct accordingly.
Create a class called MyObject as same as your json dictionary
Create a let/var property parameters: [String]?. It's optional as API isn't reliable and maybe wont send anything at all.
See the example below how I parse the json object below.
class MyObject {
let parameters: [String]?
// it's failable because maybe json different at runtime & couldn't parse
init?(json: [String:AnyObject]) {
var key = "Parameter"
var parms = [String]()
for i in 0..<json.count {
guard let item = json["\(key)\(i+1)"] as? String else { continue }
params.append(item)
}
self.parameters = params
}
}
Now you can access the parameters array with index.
Well this could be refactored and you can get the idea how you will handle this with that library.
I am inserting an Array into my database as a String and after fetching it I want it to convert it again to Array. So that I can fetch my values again and I can do next operation.
Here below is my array inserting into database(TestQuestion) as a String:
let testQuestionModel : TestQuestion = NSEntityDescription.insertNewObject(forEntityName: "TestQuestion", into: AppDelegate.getContext()) as! TestQuestion
testQuestionModel.optionsArray = "\(question["options"] as! NSArray)"
Example: String Array I am getting from Database
(\n \"Rahul Abhyankar\",\n \"Pinkesh Shah\",\n \"Ramanan
Ganesan\",\n \"Dr. Marya Wani\",\n \"\",\n \"\"\n)".
Here is 4 options you can see this is my string after fetching from Database.
1) Rahul Abhyankar.
2) Pinkesh Shah.
3) Ramanan Ganesan.
4) Dr. Marya Wani.
Now how can I convert it into array?
I tried some methods.
let arr = NSArray(object: quetion.optionsArray!).
But I am getting only one object. How can I get my array values same as previous from this string array?
I don't know about the actual type of the "option" in your code, so I set up a fake Elem struct to represent it. The remaining logic is independent of the type as long as you provide a conversion logic to and from String.
struct Elem {
// let's say this is your element type in your array
let foo: Int;
}
extension Elem: CustomStringConvertible {
var description: String {
// provide a logic to convert your element to string
return "\(foo)";
}
}
let arrayToSave = [
Elem(foo: 1),
Elem(foo: 2),
Elem(foo: 3)
]
extension Elem {
init(string: String) {
// provide a function to construct your element type from a string
self.init(foo: Int(string)!)
}
}
let stringToSave = arrayToSave.map { $0.description }.joined(separator: "|")
// save this string
// at some point retrieve it from database, which hopefully same as the saved one
let retrivedString = stringToSave;
let retrivedArray = retrivedString.split(separator: "|").map { Elem(string: String($0)) }
print(retrivedArray) // [1, 2, 3]
Here below is my array inserting into database (TestQuestion) as a
String :
let testQuestionModel : TestQuestion = NSEntityDescription.insertNewObject(forEntityName: "TestQuestion", into: AppDelegate.getContext()) as! TestQuestion
testQuestionModel.optionsArray = "\(question["options"] as! NSArray)"
No, and No.
You are using -description method of an array to save it. Clearly no.
What's wrong? Apple can't affirm that in next OS release, it won't add an extra character. In some more complex cases, it's added <NSArray <0x address> or stuff similar like that.
Suggestion 1:
Modify your entity to have an ARRAY (or usually a Set) of String.
Learn about Core-Data relationship (but that's clearly a DataBase basic knownledge). A relationship one to many should be the thing to do.You could even keep in memory what were the choices, by adding for creating the entity Options, with a String property name (name of the option), another one boolean isChecked, etc.
Suggestion 2:
If you have a limited number of options (like says one to 5), add 5 options string to your entity, and iterate to set them
testQuestionModel.option1 = question["option"][0]
testQuestionModel.option2 = question["option"][1] (if it's of course not out of range for the array)
...
Suggestion 3:
Not really recommended (in my opinion it's missing the whole advantage of the database, especially fetch and predicates, on previous sample you could fetched easily which options were checked), but if you still want to save them as a String, save them as JSON (ie. stringified).
In pseudo code (I'm not sure about the exact syntax, there are no fail safe like try/catch, optional/wrapping):
let options = questions["options"] as [String]
let jsonData = JSONSerialization.data(withJSONObject: (question["options"], options:[])
let jsonString = String.init(data:jsonData encoding:.utf8)
To retrieve them:
let options = JSONSerialization.jsonObject(with data: myJSONString.data(encoding:.utf8), options:[]) as [String]
done using Library SwiftyJSON.
if let dataFromString = yourString?.data(using: String.Encoding.utf8, allowLossyConversion: false) {
do{
let json = try JSON(data: dataFromString)
print(json)
let arrayValue = json.rawValue as! NSArray
print(arrayValue)
} catch{
print(error.localizedDescription)
}
}
Source: https://github.com/SwiftyJSON/SwiftyJSON
I have recieved a response object (res) in swift from REST API. It is of type. __NSArrayM. It contains a JSON format string which I want to parse.
{ JsonResult = "[ { \"IsAuth\":\"true\" } ]"; }
It is a long JSON String and I have shortened it for simplicity.
To parse a json, the object needs to be of type Dictionary but I can't cast the object of type __NSArrayM into it.
I searched a lot but can't figure out anyway to read this JSON string.
Additional: Whichever object I try to cast the response object. I get the error -
Could not cast value of type '__NSArrayM' (0x107e86c30) to 'NSData' (0x107e86168) or whichever data type I cast into.
Let's do this step by step.
You say you have an object named "res" which is of type __NSArrayM and which contains this thing:
{ JsonResult = "[ { \"IsAuth\":\"true\" } ]"; }
It means that you already have converted the JSON to an object, namely an NSArray.
In this array that we don't see, this thing you're showing us is a dictionary (that we will name "dict") with its value being a String which itself represents another JSON object.
Let's get the value using the key:
if let value = dict["JsonResult"] as? String {
print(value)
}
Now "value" is supposed to be "[ { \"IsAuth\":\"true\" } ]".
This is a String which represents JSON. To decode the JSON, we first have to make the string into data then we can decode:
if let data = value.data(using: .utf8) {
if let content = try? JSONSerialization.jsonObject(with: data, options: []),
let array = content as? [[String: Any]]
{
print(array)
}
}
I'm trying to populate a UITableView from the results from a call to a web service. The data is returned in JSON format as below
[{"name":"CONTROL TEST",
"nc_lead":"TOM SMITH",
"datastr":"N/A",
"username":"tsmith",
"status":"REOPENED",
"orderno":"00000000",
"ccsText":"000",
"risk":0,
"dateTimeCreated":"2016-01-29 13:16:50",
"supplyStart":"2016-02-08T11:51:00+0000",
"supplyEnd":"2016-02-08T12:03:00+0000",
"logs":
[{"dateTime":"2016-02-02 11:26:18",
"statusChangeDateTime":"2016-02-02 00:00:00",
"user":"tsmith",
"uid":1,
"task":"TESTING",
"info":"state changed to 'Y'",
"x":456123,
"y":362514,
"id_log":28294},
{“dateTime":"2016-02-02 10:54:34",
"statusChangeDateTime":"2016-02-02 10:54:00",
"user":"tsmith",
"uid":1,
"task":"TESTING",
"info":"T Smith changed area.",
"x":452356,
"y":325489,
"id_log":28291
},.....
There is no key as the first part is formed by 12 values as a header and then the logs form an array of values for each header. I return my JSON object using the code below, parsing the data object from my web service call.
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
I can see the return value for data using the code below
let str = NSString(data: data!, encoding: NSUTF8StringEncoding)
then I've tried using code such as the code below to extract a value for 'name' but it doesn't work
if let name = json["name"] as? [[String: AnyObject]] {}
How can I iterate through my json object to get the data from the header and the logs array?
It seems json object is an array of dictionary, so you should do something like this:
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments) as? Array<Dictionary<String, AnyObject>> {
for item in json {
if let dict = item as? Dictionary<String, AnyObject> {
print(dict["name"])
}
}
}
The conversion should be to AnyObject because sometimes the value is String, like for example dict["name"] == "CONTROL TEST", but dict["logs"] is Array<Dictionary<String, String>>. Do you see it?
I'm creating an app that should retrieve some JSON from a database.
This is how my JSON looks:
[{"id":"1","longitude":"10","latitude":"10","visibility":"5","timestampAdded":"2015-10-01 15:01:39"},{"id":"2","longitude":"15","latitude":"15","visibility":"5","timestampAdded":"2015-10-01 15:06:25"}]
And this is the code i use:
if let jsonResult = JSON as? Array<Dictionary<String,String>> {
let longitudeValue = jsonResult[0]["longitude"]
let latitudeValue = jsonResult[0]["latitude"]
let visibilityValue = jsonResult[0]["visibility"]
print(longitudeValue!)
print(latitudeValue!)
print(visibilityValue!)
}
As you can see it only gets the first chunk from the JSON and if there are no JSON at all it will crash, but if i want it to count the amount and make an array out of it like this:
var longitudeArray = [10, 15]
var latitudeArray = [10, 15]
And so on...
I also need this to be apple watch compatible so i can't use SwiftyJSON.
What do i do? I really hope you can help me!
Thanks.
SOLVED!
Problems was solved by "Eric D."
This is the code:
do {
if let url = NSURL(string: "YOU URL HERE"),
let data = NSData(contentsOfURL: url),
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [[String:AnyObject]] {
print(jsonResult)
let longitudeArray = jsonResult.flatMap { $0["longitude"] as? String }
let latitudeArray = jsonResult.flatMap { $0["latitude"] as? String }
print(longitudeArray)
print(latitudeArray)
}
} catch let error as NSError {
print(error.description)
}
Thank you soo much Eric!! :-)
You could use flatMap to get an array of your elements:
let longitudeArray = jsonResult.flatMap { $0["longitude"] as? String }
let latitudeArray = jsonResult.flatMap { $0["latitude"] as? String }
etc.
flatMap is like map but unwraps optionals, which is adequate because we need to safely cast the type of the object we get from each dictionary in the json array.
$0 represents the object in the current iteration of flatMap of the array it's applied to.
If you're currently using SwiftyJSON, then that would be:
let longitudeArray = jsonResult.flatMap { $1["longitude"].string }
let latitudeArray = jsonResult.flatMap { $1["latitude"].string }
because .string is SwiftyJSON's optional String value getter.
But as you said, you don't want to use it (anymore), so you need to use NSJSONSerialization to decode your JSON data, there's plenty of examples on the Web and on SO. Then you will be able to use my original answer.
You're already getting an array with all of the elements (not just the first one. you're simply only accessing the first one). jsonResult is an array of dictionaries. Each dictionary (in this case, based on the json you provided) contains these elements: id, longitude, latitude, visibility and timestampAdded. In order to access each of them, you can simply loop over jsonResult and access the i'th element (and not always the 0 element). This will also prevent the crash you're experiencing with the json is blank or invalid (since you'll only be going over the valid elements in jsonResult.
This will give you the flexibility to create the custom arrays you wish to create (in order to create an array of all of the longitudes, for example, you will simply add that element to the new array while looping over jsonResult). However, if you'd like to save yourself the trouble of manually building these arrays and assuming you have control over the json structure, I would recommend changing the received json to the relevant structure (a dictionary or arrays instead of an array of dictionaries), so it would better fit your needs and provide you the results in the relevant format right "out of the box".