Swift - JSON array values - json

I am getting following JSON values in output:
[["category_title": Shelly], ["category_title": Thaddeus],
["category_title": Chantale], ["category_title": Adara],
["category_title": Mariko], ["category_title": Felicia]]
But I want it like below:
["Shelly","Thaddeus","Chantale", "Adara","Mariko","Felicia"]
I have the following Swift code. Please help me get above output.
func successGetTermsData(response: Any){
var UserRole : String = ""
var arrayOfDetails = response as? [[String: Any]] ?? []
UserRole = arrayOfDetails as? String ?? ""
print(arrayOfDetails)
}

You have to map the array of Dictionary arrayOfDetails to an array of String. flatMap ignores a missing key.
if let arrayOfDetails = response as? [[String: String]] {
let userRole = arrayOfDetails.flatMap { $0["category_title"] }
print(userRole)
}

There are many ways to do this. One way is to use flatmap to get just the values in your array of dictionaries:
let arrayOfValues = arrayOfDetails.flatMap { $0.values }
In order to get this to work, the names need to be inside double quotes: "Shelly", etc.

Related

Get JSON Element in Swift 3

Please excuse me if this is a simple question, but I am stuck. I have tried to read everything I can to work it out myself.
I am trying to extract a URL from JSON data, I get the JSON data fine and I can print it to the console, however I can't work out how to access the URL for the audio file.
This is the code I use to get the JSON:
let session = URLSession.shared
_ = session.dataTask(with: request, completionHandler: { data, response, error in
if let response = response,
let data = data,
let jsonData = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) {
if let dictionary = jsonData as? [String: Any] {
if let prounce = dictionary["pronunciations"] as? [String: Any]{
if let audioPath = prounce["audioFile"] as? String {
print(audioPath)
}
}
}
print(response)
print(jsonData)
} else {
print(error)
print(NSString.init(data: data!, encoding: String.Encoding.utf8.rawValue))
}
}).resume()
The output I get is:
metadata = {
provider = "Oxford University Press";
};
results = (
{
id = maladroit;
language = en;
lexicalEntries = (
{
entries = (
{
etymologies = (
"late 17th century: French"
);
grammaticalFeatures = (
{
text = Positive;
type = Degree;
}
);
senses = (
{
definitions = (
"inefficient or inept; clumsy:"
);
examples = (
{
text = "both men are unhappy about the maladroit way the matter has been handled";
}
);
id = "m_en_gb0494140.001";
}
);
}
);
language = en;
lexicalCategory = Adjective;
pronunciations = (
{
audioFile = "http://audio.oxforddictionaries.com/en/mp3/maladroit_gb_1.mp3";
dialects = (
"British English"
);
phoneticNotation = IPA;
phoneticSpelling = "\U02ccmal\U0259\U02c8dr\U0254\U026at";
}
);
text = maladroit;
}
);
type = headword;
word = maladroit;
}
);
}
I want to get the URL called audioFile in the pronunciations. Any help is much appreciated.
If my guess is right, your output shown above lacks opening brace { at the top of the output.
(I'm also assuming the output is taken from your print(jsonData).)
Your jsonData is a Dictionary containing two values:
A dictionary value for "metadata"
An array value for "results"
So, you cannot retrieve a value for "pronunciations" directly from jsonData (or dictionary).
You may need to:
Retrieve the value for "results" from jsonData, it's an Array
Choose one element from the "results", it's a Dictionary
Retrieve the value for "lexicalEntries" from the result, it's an Array
Choose one element from the "lexicalEntries", it's a Dictionary
Retrieve the value for "pronunciations" from the lexicalEntry, it's an Array
Choose one element from the "pronunciations", it's a Dictionary
Here, you can access the values in each pronunciation Dictionary. In code, you need to do something like this:
if
let dictionary = jsonData as? [String: Any],
let results = dictionary["results"] as? [[String: Any]],
//You need to choose one from "results"
!results.isEmpty, case let result = results[0],
let lexicalEntries = result["lexicalEntries"] as? [[String: Any]],
//You need to choose one from "lexicalEntries"
!lexicalEntries.isEmpty, case let lexicalEntry = lexicalEntries[0],
let pronunciations = lexicalEntry["pronunciations"] as? [[String: Any]],
//You need to choose one from "lexicalEntries"
!pronunciations.isEmpty, case let pronunciation = pronunciations[0]
{
//Here you can use `pronunciation` as a Dictionary containing "audioFile" and some others...
if let audioPath = pronunciation["audioFile"] as? String {
print(audioPath)
}
}
(You can use let result = results.first instead of !results.isEmpty, case let result = results[0], if you always use the first element for arrays. Other two lines starting from !...isEmpty, case let... as well.)
You need to dig into the target element from the outermost element step by step.

Turning json variables into swift variables

My PHP server-side returns a JSON like this:
[{"scan_status":"ok","visitorData":[{"visitorCompany":"xyl","visitorStreet":"street","visitorBranche":"health","visitorEmail":"wesweatyoushop#gmail.com","lastmodified":"2014-12-15 14:18:55"}]}]
Now in Swift I would like to store this data, and for this I am trying to parse the data into Swift variables, however I got stuck.
do {
//check wat we get back
let jsonData = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves )
let vData = jsonData[0]["visitorData"]
//let vCompany = vData["visitorCompany"]
print("Test vData: \(vData)")
}
This prints
Test vData: Optional(( { visitorStreet = street; visitorPhone = 01606478; visitorCompany = xyl; visitorBranche = Sports; visitorEmail = "health#gmail.com"; lastmodified = "2014-12-15 14:18:55"; } ))
but when I try to get visitorCompany with
let vCompany = vData["visitorCompany"]
I get a compile error:
Cannot subscript a value of type 'AnyObject?!' with an index of type 'String'
BTW, why do we see the equals sign in swift i.e. visitorStreet = street?
This is because the compiler doesn't know the type of your decoded objects.
Help the compiler using casting with if let:
do {
let jsonData = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves )
if let vData = jsonData[0]["visitorData"] as? [[String:AnyObject]] {
if let vCompany = vData[0]["visitorCompany"] {
print(vCompany)
}
}
}
let vData = jsonData[0]["visitorData"] populates vData with a generic AnyObject?, because Swift can't know what kind of objects PHP returns in the JSON.
You need to do a an optional cast to another dictionary before you can use vData like you want: jsonData[0]["visitorData"] as? [String:AnyObject].
And because a conditional cast returns an optional, it's best you do an optional binding to unwrap that optional, resulting in a code similar to this:
if let vData = jsonData[0]["visitorData"] as? [String:AnyObject] {
//let vCompany = vData["visitorCompany"]
print("Test vData: \(vData)")
}
Or even better, as jsonData can not be an array, or it could be an empty array (the server malfunctions and sends an invalid json for example), you can go even further with the validation:
if let items = jsonData as? [[String:AnyObject]], vData = items.first?["visitorData"] {
//let vCompany = vData["visitorCompany"]
print("Test vData: \(vData)")
}
items = jsonData as? [[String:AnyObject]] fails if jsonData is not an array, while vData = items.first?["visitorData"] fails if items.first is nil (optional chaining here), or if items.first doesn't have a visitorData key.
Try with this:
let vData = jsonData[0]["visitorData"]![0] as! [String:AnyObject]

JSON with Swift 2, Array Structure

I'm Having trouble with JSON and Swift 2.
I'm getting this Array from the server
[{"KidName":"Jacob","KidId":1,"GardenID":0},
{"KidName":"Sarah","KidId":2,"GardenID":0},
{"KidName":"Odel","KidId":3,"GardenID":0}]
I'm familiar with JSON and I know it's not the recommended way to get a JSON, since it's supposed to be something like
{"someArray":[{"KidName":"Jacob","KidId":1,"gardenID":0}, .....
So my first question is it possible to run over the first JSON I've post and get the KidName number without editing the JSON and Add to it a JSON OBJECT to hold the array ?
my second question is really with Swift 2, how can I get the KidName (after I've edited the JSON to have an holder for the array)?
this is my code... (please read the Notes I've added)
BTW, I'm familiar with SwiftyJSON as well...
// Method I've build to get the JSON from Server, the Data is the JSON
sendGetRequest { (response, data ) -> Void in
// need to convert data to String So I can add it an holder
if let str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String {
/**
after editing the str, i'm Having a valid JSON, let's call it fixedJSON
*/
let fixedJSON = "{\"kidsArray\":\(dropLast)}"
// Now I'm converting it to data back again
let jsonTodata = fixedJSON.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
// After Having the data, I need to convert it to JSON Format
do{
let dataToJson = try NSJSONSerialization.JSONObjectWithData(jsonTodata, options: []) as! [String:AnyObject]
//Here I'm getting the KidID
if let kidID = jsonSe["kidsArray"]![0]["KidId"]!!.integerValue {
print("kidID in first index is: \(kidID)\n")
}
//NOW trying to get the KidName which not working
if let kidname = jsonSe["kidsArray"]![0]["KidName"]!!.stringValue {
print("KidName is \(kidname)\n")
}
}
So as you can see, I'm not able to get the KidName.
Any Help Would be Appreciate.
You can use the following function to get the 'someArray' array and then use this getStringFromJSON function to get the 'KidName' value.
func getArrayFromJSON(data: NSDictionary, key: String) -> NSArray {
if let info = data[key] as? NSArray {
return info
}
else {
return []
}
}
let someArray = self.getArrayFromJSON(YourJSONArray as! NSDictionary, key: "someArray")
func getStringFromJSON(data: NSDictionary, key: String) -> String {
if let info = data[key] as? String {
return info
}
return ""
}
let KidName = self.getStringFromJSON(someArray as! NSDictionary, key: "KidName")
Hope this might be useful to you.

SwiftyJSON looping through an array of JSON objects

[
{
"cont": 9714494770,
"id": "1",
"name": "Kakkad"
},
{
"cont": 9714494770,
"id": "2",
"name": "Ashish"
}
]
The one above is a json array filled with JSON objects. I don't know how to parse through this with SwiftyJSON
Example from the SwiftyJSON page, adapted to your data:
let json = JSON(data: dataFromNetworking)
for (index, object) in json {
let name = object["name"].stringValue
println(name)
}
Assuming [{"id":"1", "name":"Kakkad", "cont":"9714494770"},{"id":"2", "name":"Ashish", "cont":"9714494770"}] is assigned to a property named jsonData.
let sampleJSON = JSON(data: jsonData)
let sampleArray = sampleJSON.array sampleArray is an optional array of JSON objects.
let firstDict = sampleArray[0] firstDict is an optional JSON dict.
let name = firstDict["name"] is an optional JSON object
let virtName = name.string is a optional string (In this case "Kakkad").
let realName = name.stringValue realName is a string or an empty string.
You could also use:
let longName = sampleJSON[0]["name"].stringValue
After you initialize the JSON object with data all of the elements are JSON types until you convert them to a swift type.
.string optional (string or null)
.stringValue string or "" empty
string
.dict optional ([String: AnyObject] or null)
.dictValue
([String: AnyObject] or String: AnyObject)
For Swift4 I have updated the code from Moritz answer
if let path : String = Bundle.main.path(forResource: "tiles", ofType: "json") {
if let data = NSData(contentsOfFile: path) {
let optData = try? JSON(data: data as Data)
guard let json = optData else {
return
}
//If it is a JSON array of objects
for (_, object) in json {
let name = object["name"].stringValue
print(name)
}
}
}
Swift 3 or 4 code like this:
let json = JSON(yourData)
for (_, object) in json {
let cont = object["cont"].stringValue
print(cont)
}
You can put index instead of _ if you use is anywhere in your code. If you don't use a variable, it's better to put _ (XCode also gives warnings).

How do I save JSON array of dictionaries in Swift that maps a String to an Int or String?

I'm having a lot of difficulty with this one.
My server sends JSON arrays of dictionaries, with the dictionaries having a String as a key, with either a String or an Int as the value for the key. For example, if the key was name, it would return a string, but some values are asking for numeric things like "time since" which return Ints.
How do I handle this in Swift?
My first attempt was:
let dictArray = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &jsonError) as Dictionary<String, Any>[]
But I get:
fatal error: can't unwrap Optional.none
If I change Any to AnyObject I can't cast it as an Int for some keys, it complains about the subscript.
What should I be doing?
The Cocoa to Swift binding maps id as AnyObject. And since the keys are not guaranteed to exist in the dictionary, the subscript returns AnyObject?.
Along those lines still seems to be problem with Xcode beta2.
For example, this crashes reproducibly the swift REPL:
let a : AnyObject? = nil
let b : Any? = a
So that might be the reason as well, why casting to Dictionary<String, Any>[] does not work.
Either way you might be better off using the "literal" mapping Dictionary<String, AnyObject>[] and checking the types yourself.
When casting AnyObject? to Int you have to remember that you are actually dealing with an optional. That means you have to unwrap it first using ! or an if let construct.
Alternatively you can just iterate over the dictionary:
var jsonError : NSError?
if var dictArray = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &jsonError) as? Dictionary<String, AnyObject>[]
{
for dict in dictArray
{
for (key, data) in dict
{
var output : String = "(unknown)";
if let number = data as? Int
{
output = "\(number)"
}
else if let str = data as? String
{
output = str
}
println("\(key): \(output)")
}
}
}