I'm using Alamofire and SwiftyJSON and I want to check if the response contains a value that I will type in a search bar.
I've just got the whole JSON file of 1666 objects and append it into my objects array and then I'm searching for value, but it takes too long.
func parseJSON(json: JSON, parse: ParseType) {
var i = 0
var j = 0
switch parse {
case .group:
for elements in json["groups"] {
if let groupId = json["groups"][i]["id"].int {
let groupName = json["groups"][i]["name"].string
// print(groupId)
let group = Groups(id: groupId, name: groupName!)
groupsArray.append(group)
i += 1
} else {
print("Error can't parse JSON")
}
}
func getGroupsData(url: String, groupName: String) {
Alamofire.request(url, method: .get).responseJSON { (response) in
if response.result.isSuccess {
print("Is Success")
let json = JSON(response.result.value)
self.parseJSON(json: json, parse: .group)
if let group = self.groupsArray.first(where: {$0.name == groupName}) {
print("found \(group)")
let searchScheduleUrl = url + "\(group.id)"
self.getGroupSchedule(url: searchScheduleUrl)
} else {
print("Can't find group")
}
} else {
print(response.result.error)
}
}
}
And here is JSON:
{
"groups" : [
{
"faculty" : {
"id" : 101,
"abbr" : "ИнГО",
"name" : "Гуманитарный институт"
},
"id" : 26262,
"spec" : "47.06.01 Философия, этика и религиоведение",
"kind" : 3,
"level" : 3,
"name" : "33865\/4702",
"type" : "common"
},
{
"faculty" : {
"id" : 95,
"abbr" : "ИКНТ",
"name" : "Институт компьютерных наук и технологий"
},
"id" : 27432,
"spec" : "09.03.04 Программная инженерия",
"kind" : 0,
"level" : 1,
"name" : "в13534\/22",
"type" : "evening"
},
{
"faculty" : {
"id" : 92,
"abbr" : "ИСИ",
"name" : "Инженерно-строительный институт"
},
"id" : 26322,
"spec" : "08.06.01 Техника и технологии строительства",
"kind" : 3,
"level" : 1,
"name" : "13163\/0801",
"type" : "common"
}, and so on...
I want to check for example:
if name: "13541/1" is in dictionary and if it is i want to get it's id
You can try
struct Root: Codable {
let groups: [Group]
}
struct Group: Codable {
let faculty: Faculty
let id: Int
let spec: String
let kind, level: Int
let name, type: String
}
struct Faculty: Codable {
let id: Int
let abbr, name: String
}
do {
let res = try JSONDecoder().decode(Root.self,from:data)
if let item = res.groups.first(where:{ $0.name == YourName }) {
print(item.id)
}
}
catch {
print(error)
}
Related
This is the json output from https://maps.googleapis.com/maps/api/distancematrix/json?origins=rijssen&destinations=almelo&mode=driving&language=en&key=
{ "destination_addresses" : [ "Almelo, Netherlands" ],
"origin_addresses" : [ "Rijssen, Netherlands" ],
"rows" : [
{
"elements" : [
{
"distance" : {
"text" : "14.1 km",
"value" : 14090
},
"duration" : {
"text" : "21 mins",
"value" : 1267
},
"status" : "OK"
}
]
}
],
"status" : "OK"
}
this is the struct in Swift
struct Model: Codable{
let destination_addresses : [String]
let origin_addresses : [String]
let rows : [Elements]
let status : String
}
struct Elements: Codable {
let elements:[Distance]
}
struct Distance: Codable{
let distance:Value
let duration:Value
let status:String
}
struct Value: Codable{
let text:String
let value:Int
}
This is the api request
guard let url = URL(string: api) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
do {
if let data = data {
let result = try JSONDecoder().decode([Model].self, from: data)
error in compiler
The data couldn’t be read because it isn’t in the correct format.
Why is the code not working?
Thank you i.a.
Please help make this work I've been trying to figure out JSON and Swift for a week and facing this problem for 5 hours so far today.
Error Received
ERROR WHEN DECODING JSON keyNotFound(CodingKeys(stringValue: "MP", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: "MP", intValue: nil) ("MP").", underlyingError: nil))
YEAR IS NIL
Code
struct UserDay: Codable {
let MP: UserMP
let WP: UserWP
}
struct UserMP: Codable {
let M: [UserM]
let S: [UserS]
}
struct UserM : Codable {
let title: String
let description: String
let time: String
}
struct UserS : Codable {
let title: String
let description: String
let time: String
}
struct UserWP: Codable {
let WP: [WPData]
}
struct WPData: Codable {
let title: String
let values: [Int]
}
class LogDataHandler {
public func grabJSONInfo(){
guard let jsonURL = Bundle(for: type(of: self)).path(forResource: "newLogData", ofType: "json") else { return }
guard let jsonString = try? String(contentsOf: URL(fileURLWithPath: jsonURL), encoding: String.Encoding.utf8) else { return }
// print(jsonString)
// Print Info for TESTING
var year: UserDay?
do {
year = try JSONDecoder().decode(UserDay.self, from: Data(jsonString.utf8))
} catch {
print("ERROR WHEN DECODING JSON \(error)")
}
guard let results = year else {
print("YEAR IS NIL")
return
}
print(results)
}
}
JSON
{
"01/01/2020": {
"MP" : {
"M" : [
{"title" : "m1", "description" : "1", "time" : "12:30pm"},
{"title" : "m2", "description" : "2", "time" : "1:30pm"},
{"title" : "m3", "description" : "3", "time" : "2:30pm"}
],
"S" : [
{"title" : "s1", "description" : "1", "time" : "1pm"}
]
},
"WP" : [
{ "title" : "abc", "values" : [12, 10, 6]},
{ "title" : "def", "values" : [8]}
]
},
"01/29/2020": {
"MP" : {
"M" : [{"title" : "m1", "description" : "1", "time" : "12:30pm"}],
"S" : [{"title" : "s1", "description" : "1", "time" : "12:30pm"}]
},
"WP" :[{ "title" : "def", "values" : [8]}]
}
}
First, replace let WP: UserWP with an array:
struct UserDay: Codable {
let MP: UserMP
let WP: [WPData]
}
Then decode [String:UserDay] instead of UserDay:
try JSONDecoder().decode([String:UserDay].self, from: Data(jsonString.utf8))
Note that this will return a dict with key-value pairs "01/01/2020":UserDay object.
This means you can't assign a dictionary [String: UserDay] to a UserDay variable. Instead you can access the dict by a key which is some date (eg. "01/01/2020") and then assign it to your UserDay variable:
let result = try JSONDecoder().decode([String:UserDay].self, from: Data(jsonString.utf8))
let someYear = result["01/01/2020"]
Note that someYear will be optional so you may want to provide a default value or force-unwrap it.
I am a beginner programmer and I couldn't parse my json file. I can see datas in my console but I need help to parse json datas. I shared my json datas from url and I would like to parse with Alamofire. I installed PodFile with Alamofite and SwiftyJSON. I don't have any error but I need help for parse it.
Also I created string Arrays for following datas. I will append data in arrays.
[
{
"id" : 1,
"team" : "Liverpool",
"players" : [
{
"id" : 2,
"name" : "Alisson",
"position" : "Goal Keeper",
"number" : "13"
},
{
"id" : 3,
"name" : "Salah",
"position" : "Forward",
"number" : "10"
}
],
"trophies" : [
"2019 champions league",
"2005 champions league"
],
"logoUrl" : "url"
},
{
"id" : 4,
"team" : "Real Madrid",
"players" : [
{
"id" : 5,
"name" : "Ramos",
"position" : "Defender",
"number" : "4"
},
{
"id" : 6,
"name" : "Benzema",
"position" : "Forward",
"number" : "9"
}
],
"trophies" : [
"2018 champions league",
"2017 champions league",
"2016 champions league"
],
"logoUrl" : "url"
}
]
import Alamofire
import SwiftyJSON
func fetchJsonData(){
DispatchQueue.main.async {
Alamofire.request(url).responseData { response in
guard let data = response.data else { return }
do {
let res = try JSONDecoder().decode([PageData].self, from:data)
print(res)
} catch {
print("having trouble converting it to a dictionary" , error)
}
}
}
}
// this is my modal file
struct PageData: Codable {
let team: String
let players: [Player]
let trophies: [String]
let logoUrlL: String
}
struct Player: Codable {
let id: Int
let name,position, number: String?
}
You need responseData for using JSONDecoder
Alamofire.request(url).responseData { response in
guard let data = response.data else { return }
do {
let res = try JSONDecoder().decode([PageData].self, from:data)
print(res)
} catch {
print("having trouble converting it to a dictionary" , error)
}
}
Also players and trophies are arrays
struct PageData: Codable {
let team: String
let players: [Player]
let trophies: [String]
let logoUrlL: String
}
struct Player: Codable {
let id: Int
let name,position, number, type, quantity: String?
}
This is my json:
[
{
"category" : {
"id" : 1,
"text" : "cat1"
},
"id" : 1,
"title" : "book1"
},{
"category" : {
"id" : 2,
"text" : "cat2"
},
"id" : 2,
"title" : "book2"
},{
"category" : {
"id" : 1,
"text" : "cat1"
},
"id" : 3,
"title" : "book3"
}
]
How can I grouping it by category? i want to use them in different collectionView
Thank you in advance
Define your JSON codable classes as follows.
typealias Result = [ResultElement]
struct ResultElement: Codable {
let category: Category
let id: Int
let title: String
}
struct Category: Codable {
let id: Int
let text: String
}
Now, Iterate Result array after JSON parsing using JSONDecoder and compare Category struct by equal operator and group it. Since Int and String inside Category struct conforms to Equatable protocol by default, Category struct can also be compared using Equatable protocol.
You can try
let str = """
[
{
"category" : {
"id" : 1,
"text" : "cat1"
},
"id" : 1,
"title" : "book1"
},{
"category" : {
"id" : 2,
"text" : "cat2"
},
"id" : 2,
"title" : "book2"
},{
"category" : {
"id" : 1,
"text" : "cat1"
},
"id" : 3,
"title" : "book3"
}
]
"""
do {
let res = try JSONDecoder().decode([Root].self, from: Data(str.utf8))
print(res)
let dic = Dictionary(grouping: res, by: { $0.category.text})
print(dic) // this dictionary is your new data source key is title of section value is sections rows
}
catch {
print(error)
}
struct Root: Codable {
let category: Category
let id: Int
let title: String
}
struct Category: Codable {
let id: Int
let text: String
}
Create Structs
//MARK: - MyData
public struct MyData {
public var category : Category
public var id : Int
public var title : String
}
//MARK: - Category
public struct Category {
public var id : Int
public var text : String
}
Create Model
func createData () -> [MyData] {
let c1 = Category.init(id: 1, text: "Cat1")
let d1 = MyData.init(category: c1, id: 1, title: "Book1")
let c2 = Category.init(id: 2, text: "Cat2")
let d2 = MyData.init(category: c2, id: 2, title: "Book2")
let c3 = Category.init(id: 1, text: "Cat1")
let d3 = MyData.init(category: c3, id: 3, title: "Book3")
return [d1, d2, d3]
}
Group your data
let ungroupedData = createData()
print("Ungrouped\n")
print(ungroupedData)
let groupedData = Dictionary(grouping: ungroupedData, by: {$0.category.text})
print("\nGrouped\n")
print(groupedData)
groupedData["Cat1"] // get cat1 array list
{
"uri" : "http://www.edamam.com/ontologies/edamam.owl#recipe_f9e656dd9d2b4db9816340687d01722c",
"calories" : 38,
"totalWeight" : 113.25,
"dietLabels" : [ "LOW_FAT" ],
"healthLabels" : [ "SUGAR_CONSCIOUS", "VEGAN", "VEGETARIAN", "PEANUT_FREE", "TREE_NUT_FREE", "ALCOHOL_FREE" ],
"cautions" : [ ],
"totalNutrients" : {
"ENERC_KCAL" : {
"label" : "Energy",
"quantity" : 38.505,
"unit" : "kcal"
},
"FAT" : {
"label" : "Fat",
"quantity" : 0.41902500000000004,
"unit" : "g"
},
"FASAT" : {
"label" : "Saturated",
"quantity" : 0.044167500000000005,
"unit" : "g"
},
"FAMS" : {
"label" : "Monounsaturated",
"quantity" : 0.0124575,
"unit" : "g"
},
"FAPU" : {
"label" : "Polyunsaturated",
"quantity" : 0.043035000000000004,
"unit" : "g"
}
}
}
/*
* networking method
*/
func getNutritionData(url: String) {
Alamofire.request(url, method: .get)
.responseString { response in
if response.result.isSuccess {
print("Sucess! Got the Nutrition data")
let nutritionJSON : JSON = JSON(response.result.value!)
//print(nutritionJSON)
self.updateNutritionData(json: nutritionJSON)
} else {
print("Error: \(String(describing: response.result.error))")
self.caloriesLable.text = "Connection Issues"
}
}
}
func updateNutritionData(json: JSON) {
let calories = json["calories"].intValue
print(calories)
}
^ When I try to get the calories for example, I get nil
In the nutritionData method I tried using .responseJSON but it was throwing an error so I switched to .responseString. I want to get the "totalNutrients" information from that JSON. Help would be appreciated
It's better to use method with responseJSON instead of responseString
Alamofire.request(url, method: .get, parameters:nil, encoding: JSONEncoding.default).responseJSON { response in
print(response)
if let json = response.result.value as? [String:Any] {
print(json["calories"])
}
}
and then try
Ary alamofire.response, and then directly parse data in to JSON
Alamofire.request(url, method: .get).response { response in
if response.result.isSuccess {
let nutritionJSON : JSON = JSON(response.data)
self.updateNutritionData(json: nutritionJSON)
} else {
print("Error: \(String(describing: response.result.error))")
self.caloriesLable.text = "Connection Issues"
}
}
func updateNutritionData(json: JSON) {
let calories = json["calories"].intValue
print(calories)
}
You should definitely be using responseJSON() if you just wanna serialize JSON. If you're trying to use it with a Decodable object, you should be using responseData() and decoding one of your custom types with the data. Always validate.
func getNutritionData(url: String) {
Alamofire.request(url)
.validate(statusCode: 200...200)
.validate(contentType: ["application/json"])
.responseJSON { (response) in
switch response.result {
case .success(let json):
// Do something with the json.
let dict = json as? [String: Any]
print(dict["<KEY>"]!)
case .failure(let error):
print(error)
}
}
}