Got the following JSON! I’m trying to get a single url from those tree inside images array! Can anyone please explain me how I can get it.
let dataTask = session.dataTask(with: request) { (data, response, error) in
do {
let json = try? JSONSerialization.jsonObject(
with: data!,
options: JSONSerialization.ReadingOptions.mutableContainers
) as! [String: AnyObject]
if let artists = json?["artists"] as? [String: AnyObject] {
if let items = artists["items"] {
for i in 0..<items.count {
let item = items[i] as? [String: AnyObject]
let name = item?["name"] as! String
self.nameArray.append(name)
let popularity = item?["popularity"] as! Int
self.popuArray.append(popularity)
if let artists = item["artists"] as? String: AnyObject {
if let images = artists["images"] as? [String: AnyObject] {
let imageData = images[0]
}
}
print(name)
print(popularity)
}
}
}
}
}
I am able to get the values from name and popularity.
No way for this url… inside images!
My json is a spotify.. api
Looks like this:
{
"artists": {
"href": "https://api.spotify.com/v1/search?query=Metallica&type=artist&market=CA&offset=0&limit=20",
"items": [
{
"external_urls": {
"spotify": "https://open.spotify.com/artist/2ye2Wgw4gimLv2eAKyk1NB"
},
"followers": {
"href": null,
"total": 3455148
},
"genres": [
"alternative metal",
"alternative rock",
"hard rock",
"metal",
"rock",
"speed metal",
"thrash metal"
],
"href": "https://api.spotify.com/v1/artists/2ye2Wgw4gimLv2eAKyk1NB",
"id": "2ye2Wgw4gimLv2eAKyk1NB",
"images": [
{
"height": 640,
"url": "https://i.scdn.co/image/5a06711d7fc48d5e0e3f9a3274ffed3f0af1bd91",
"width": 640
},
{
"height": 320,
"url": "https://i.scdn.co/image/0c22030833eb55c14013bb36eb6a429328868c29",
"width": 320
},
{
"height": 160,
"url": "https://i.scdn.co/image/c1fb4d88de092b5617e649bd4c406b5cab7d3ddd",
"width": 160
}
],
"name": "Metallica",
"popularity": 83,
"type": "artist",
"uri": "spotify:artist:2ye2Wgw4gimLv2eAKyk1NB"
}
]
}
}
I want to pick any url i want from those 3.
It appears you just need to update this line..
if let images = artists["images"] as? [String: AnyObject] {
to
if let images = artists["images"] as? [[String: AnyObject]] {
if let firstImage = images.first, let urlString = firstImage["url"] as? String {
let url = URL(string: urlString)
}
}
[String:AnyObject] casts to a Dictionary object, [[String:AnyObject]] casts to an Array of Dictionary objects which is what you need in this case
Related
I'm trying to access an array response within array this is how I'm getting the friends array successfully
let url = URL(string: "http://xyz/api/get-friends-in-meetings")
AF.request(url!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: headers).responseJSON{ response in
switch response.result {
case .success:
let responseValue = response.value as! NSDictionary
let friends: [NSDictionary] = responseValue["friends"] as! [NSDictionary]
//here I want to store the "meeting array so that I can use it later"
break
case .failure(let error):
print(error)
break
}
}
This is the JSON response
{
"status": 0,
"message": "Friends found.",
"friends": [
{
"id": 24,
"name": "XYZ",
"email": "Z#Y.Z",
"meetings": [
{
"meeting_with": "X",
"meeting_person_screen_name": "Y",
"meeting_purpose": "Z",
}
]
}
]
}
how do I get the "meetings" array which is within the "friends" array? I have tried the same way as I did for friends but it show an error No exact matches in call to subscript
First you need to define these structs:
struct DataResult : Decodable {
let status: Int
let message: String
let friends: [FriendsResult]
}
struct FriendsResult : Decodable {
let id: Int
let name: String
let email: String
let meetings: [MeetingsResult]
}
struct MeetingsResult: Decodable {
let meeting_with: String
let meeting_person_screen_name: String
let meeting_purpose: String
}
So after that we need the JSON Example:
// Meetings
let meeting1: [String: Any] = [
"meeting_with": "X",
"meeting_person_screen_name": "Y",
"meeting_purpose": "Z"
]
// Friends
let friend1: [String: Any] = [
"id" : 24,
"name": "XYZ",
"email": "x#y.z",
"meetings": [meeting1]
]
let friend2: [String: Any] = [
"id" : 25,
"name": "John Doe",
"email": "jd#x.doe",
"meetings": [meeting1]
]
// Main JSON
let jsonExample: [String : Any] = [
"status": 0,
"message": "Friends found.",
"friends": [friend1, friend2]
]
Well, we continue to validate the JSON and decode to "DataResult":
let valid = JSONSerialization.isValidJSONObject(jsonExample)
if valid {
do {
let dataResult = try JSONSerialization.data(withJSONObject: jsonExample, options: JSONSerialization.WritingOptions())
let dataDecode = try JSONDecoder().decode(DataResult.self, from: dataResult)
let jsonString = String(data: dataResult, encoding: .utf8)
print("JSON: \(String(describing: jsonString))")
if dataDecode.friends.count > 0 {
// Get first friend you should use guard
let friend = dataDecode.friends[0]
let meeting = friend.meetings[0]
print("\(friend.name)")
print("\(meeting.meeting_with)")
}
}
catch let error {
print("ERROR: \(error.localizedDescription)")
}
}
else {
print("Invalid JSON")
}
I have a simple array that I want to decode. I can deal with arrays in a JSON format with creating a new struct in the model class, and attributing that struct as an array in the main struct. But in this case, the json data is already on an array with 1 element. Therefore I should get the first element in the json response. I think I need to provide a decoder before I can access anything, but I don't know how that decoder model should be. The error I'm getting is:
typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil))
JSON data I want to decode: (notice the data is on a array)
[
{
"name": "United States",
"topLevelDomain": [
".us"
],
"alpha2Code": "US",
"alpha3Code": "USA",
"callingCodes": [
"1"
],
"capital": "Washington, D.C.",
"altSpellings": [
"US",
"USA",
"United States of America"
],
"region": "Americas",
"subregion": "Northern America",
"population": 321645000,
"latlng": [
38,
-97
],
"demonym": "American",
"area": 9629091,
"gini": 48,
"timezones": [
"UTC-12:00",
"UTC-11:00",
"UTC-10:00",
"UTC-09:00",
"UTC-08:00",
"UTC-07:00",
"UTC-06:00",
"UTC-05:00",
"UTC-04:00",
"UTC+10:00",
"UTC+12:00"
],
"borders": [
"CAN",
"MEX"
],
"nativeName": "United States",
"numericCode": "840",
"currencies": [
"USD",
"USN",
"USS"
],
"languages": [
"en"
],
"translations": {
"de": "Vereinigte Staaten von Amerika",
"es": "Estados Unidos",
"fr": "États-Unis",
"ja": "アメリカ合衆国",
"it": "Stati Uniti D'America"
},
"relevance": "3.5"
} ]
model class:
struct CountryModel: Codable {
let country: [MyResponse]
}
struct MyResponse: Codable {
let name: String
let capital: String
}
Manager class:
struct CountryManager {
let countryURL = "https://restcountries-v1.p.rapidapi.com/name/"
func fetchData(_ countryName: String) {
let urlString = "\(countryURL)\(countryName)"
print(urlString)
performRequest(urlString)
}
func performRequest(_ urlString: String){
if let url = URL(string: urlString){
var request = URLRequest(url:url)
request.setValue("x-rapidapi-key", forHTTPHeaderField: "myapikey")
let session = URLSession(configuration: .default)
let task = session.dataTask(with: request) { (data, response, error) in
if let e = error {
print(e)
return
}
if let safeData = data {
self.parseJSON(safeData)
}
}
task.resume()
}
}
func parseJSON(_ countryData: Data) {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode([CountryModel].self, from: countryData)
print(decodedData[0].country)
}
catch {
print(error)
}
}
}
Most of the fields are missing from your model. Here is how it should look like instead:
struct Country: Codable {
let name: String
let topLevelDomains: [String]
let alpha2Code: String
let alpha3Code: String
let callingCodes: [String]
let capital: String
let altSpellings: [String]
let region: String
let subregion: String
let population: Int
let latlng: [Int]
let demonym: String
let area: Int
let gini: Int
let timezones: [String]
let borders: [String]
let nativeName: String
let numericCode: String
let currencies: [String]
let languages: [String]
let translation: Translation
let relevance: String
}
struct Translation: Codable {
let de: String
let es: String
let fr: String
let ja: String
let it: String
}
I found out that there was a problem in my http request. I used Alamofire in the request part and I don't experience the problem anymore. The issue seemed to be related to the decoding but I don't know. I'm posting the final code if anyone experiences the same issue.
import Foundation
import Alamofire
struct CountryManager {
let countryURL = "https://restcountries-v1.p.rapidapi.com/name/"
func fetchData(_ countryName: String) {
let urlString = "\(countryURL)\(countryName)"
print(urlString)
performRequest(urlString)
}
func performRequest(_ urlString: String){
let headers: HTTPHeaders = [
"x-rapidapi-host": "restcountries-v1.p.rapidapi.com",
"x-rapidapi-key": "apices"
]
AF.request(urlString, headers: headers).responseJSON { response in
self.parseJSON(response.data!)
}
}
func parseJSON(_ countryData: Data) {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(CountryAlias.self, from: countryData)
print(decodedData[0].name)
}
catch {
print(error)
}
}
}
So basically I'm trying to read a local json file about some spendings. I have a struct "Spending" and a struct "Spendings" that holds an array of Spending. I can't access the data from my json when I decode with the type Spendings.
I tried to decode with [Spending.self] which is working but I want to use my struct Spendings and I can't figure why it doesn't work?
[
{
"id": 1,
"name": "Métro 052",
"price": 8.97,
"date": "22/07/2019",
"category": "Transport"
},
{
"id": 2,
"name": "National Geographic Museum",
"price": 10.77,
"date": "22/07/2019",
"category": "Museum"
}
]
enum Categories: String, Codable {
case Transport
case Food
case Museum
case Mobile
case Housing
case Gifts
case Shopping
}
struct Spending: Codable {
var id: Int
var name: String
var price: Float
var date: String
var category: Categories
}
struct Spendings: Codable {
let list: [Spending]
}
//Not working
class SpendingController {
static let shared = SpendingController()
func fetchSpendings(completion: #escaping ([Spending]?) -> Void) {
if let filepath = Bundle.main.path(forResource: "spending", ofType: "json") {
let jsonDecoder = JSONDecoder()
if let data = try? Data(contentsOf: URL(fileURLWithPath: filepath)), let spendings = try? jsonDecoder.decode(Spendings.self, from: data) {
completion(spendings.list)
}
}
}
}
//Working
class SpendingController {
static let shared = SpendingController()
func fetchSpendings(completion: #escaping ([Spending]?) -> Void) {
if let filepath = Bundle.main.path(forResource: "spending", ofType: "json") {
let jsonDecoder = JSONDecoder()
if let data = try? Data(contentsOf: URL(fileURLWithPath: filepath)), let spendings = try? jsonDecoder.decode([Spending].self, from: data) {
completion(spendings)
}
}
}
}
I don't have any error messages but in my completion when I print the result nothing is printed contrary to when I use [Spending].self.
Decoding a [Spending].self is indeed correct here because the root of your JSON is an array, which means that the type you use to decode should be [XXX].self.
Decoding a Spendings.self would be incorrect here because it would mean that you are a decoding an object root, as opposed to an array root. The Spendings struct has a single property list, so the JSON's root object would need to have a key of "list" in order for decoding Spendings.self to work correctly, like this:
{
"list":
[
{
"id": 1,
"name": "Métro 052",
"price": 8.97,
"date": "22/07/2019",
"category": "Transport"
},
{
"id": 2,
"name": "National Geographic Museum",
"price": 10.77,
"date": "22/07/2019",
"category": "Museum"
}
]
}
I have tier to get all value from this jsonResult i want array from this like "projectArray","msg","msg2" and string like "output" ,"output_prg" i only get first array value how to get other values?
This is my result
{
"project": [{
"name": [{
"sac": "sachin",
"sag": "sagar"
}]
}, {
"output": " true",
"msg1": [{
"emp": "001",
"empname": "sachin"
}, {
"emp": "002",
"empname": "sagar"
}]
}, {
"output_prg": " true",
"msg2": [{
"id": "1",
"pr_code": "SD"
}, {
"id": "002",
"pr_code": "SJ"
}]
}]
}
This is my code
if let array = response.result.value as? NSDictionary
{
print(array)
let mainArray = array["project"] as? [[String:Any]]
print(mainArray!)
for item in mainArray!
{
print(item)
let status = item["name"]
print(status!)
}
}
Thank you in advance
Try This---->
//to get JSON return value
if let array = response.result.value as? NSDictionary
{
print(array)
let mainArray = array["project"] as? [[String:Any]]
print(mainArray?.count as Any)
if (mainArray?.count)!>0
{
let name = mainArray?[0]
let project_status = name?["name"] as? [[String:Any]]
print(name!)
}
if (mainArray?.count)!>1
{
let output = mainArray?[1]
print(output!)
}
if (mainArray?.count)!>2
{
let output_prg = mainArray?[2]
let Output_getProject = output_prg?["output_prg"]
}
}
}
Happy Coading :-)
I am trying to fetch the Json data from Api which is in the following format
[
{
"id": "244",
"name": "PIZZAS",
"image": "",
"coupon": "1",
"icon": "",
"order": "1",
"aname": "",
"options": "2",
"subcategory": [
{
"id": "515",
"name": "MARGARITA",
"description": "Cheese and Tomato",
"image": "",
"icon": "",
"coupon": "1",
"order": "1",
"aname": "",
"options": "2",
"item": [
{
"id": "1749",
"name": "9 Inch Thin & Crispy Margarita",
"description": "",
"price": "3.40",
"coupon": "1",
"image": "",
"options": "2",
"order": "1",
"addon": "495",
"aname": "",
"icon": ""
},
{
"id": "1750",
"name": "12 Inch Thin & Crispy Margarita",
"description": "",
"price": "5.20",
"coupon": "1",
"image": "",
"options": "2",
"order": "2",
"addon": "496",
"aname": "",
"icon": ""
}
]
}
How can i fetch the "subcategory name" as well as " items name". Please help me out.I have written some codes and tried to fetch but not working.
var json: NSArray!
do {
json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions()) as? NSArray
} catch {
print(error)
}
self.AllData = json.valueForKey("subcategory") as! Array<String>
print(self.AllData)
print(self.AllData.count)
But its not fetching any value
Other way also I have tried but still no data fetching . only the data is coming in json1.
do {
let json1 = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions())
// print(json1)
if let subcategory = json1["subcategory"] as? [[String: AnyObject]] {
for subname in subcategory {
if let name = subname["name"] as? String {
print(name)
}
if let items = subname["item"] as? [[String: AnyObject]] {
for item in items {
if let itemName = item["name"] as? String {
print(itemName)
}
}
}
}
}
} catch {
print(error)
}
At first its an array of objects/Dictionary.And you are creating an array of string. Thats why for subcategory it will not work.You need to create an array of Dictionaries like this:
do {
let json1 = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions())
self.AllData = json1.valueForKey("name") as! Array<String>
print(self.AllData)
print("Number of menu = \(json1.count)")
for var i in 0..<json1.count {
print(" \n \(i+1) row menu \n")
if let subs = json1[i]["subcategory"] as? [[String: AnyObject]] {
//print(subs)
for sub in subs {
if let name = sub["name"] as? String {
print("subcategory name= \t \(name)")
//print(name)
}
if let desc = sub["description"] as? String {
print("description= \t \(desc)")
// print(desc)
}
}
print("Number of subcategory= \(subs.count)")
for var i in 0..<subs.count {
if let items = subs[i]["item"] as? [[String: AnyObject]] {
print("items = ")
print(items.count)
for item in items {
if let itemName = item["name"] as? String {
print(itemName)
}
}
}
}
}
}
}catch {
print(error)
}
Try this one it will work accoording to your json data
This may just be a problem when cutting and pasting into the question, but it looks like your JSON data isn't formatted correctly (the []s and {}s don't match up). As the previous commentor said, you're dealing with an array of dictionaries not an array of strings. Try something like this:
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions())
if let subs = json[0]["subcategory"] as? [[String: AnyObject]] {
for sub in subs {
if let name = sub["name"] as? String {
print(name)
}
if let items = sub["item"] as? [[String: AnyObject]] {
for item in items {
if let itemName = item["name"] as? String {
print(itemName)
}
}
}
}
}
} catch {
print(error)
}