I need to parse out "choices" and save 123347 and save "option" to a string from the following String:
{
"type" : "radiobuttons",
"patient" : false,
"text" : "How are you today",
"id" : 63339,
"position" : 2,
"options" : "123344:ok today;123345:see you tomorrow;123346:call friend;123347:call lisa;",
"required" : true,
"choices" : {
"123347" : {
"value" : 3,
"option" : "iOS"
},
"123345" : {
"option" : "Android",
"value" : 1
},
"123346" : {
"option" : "Windows",
"value" : 2
},
"123344" : {
"option" : "MAC",
"value" : 0
}
}
}
let json = try? JSONSerialization.jsonObject(with: str, options: [])
Swift 5
Try to serialize and decode it
let jsonResponse = try JSONSerialization.data(withJSONObject: responseObject as Any, options: JSONSerialization.WritingOptions.sortedKeys)
let customObject = try JSONDecoder().decode(CustomObject.self, from: jsonResponse)
guard let requiredChoice = customObject.choices["123347"] else{
return
}
let option = requiredChoice.option
print(option)
CustomObject for your json:
struct CustomObject: Codable {
let type: String
let patient: Bool
let text: String
let id, position: Int
let options: String
let customObjectRequired: Bool
let choices: [String: Choice]
enum CodingKeys: String, CodingKey {
case type, patient, text, id, position, options
case customObjectRequired = "required"
case choices
}
}
struct Choice: Codable {
let option: String
let value: Int
}
There are many tools available to easily create struct/class for your json:
E.g: https://app.quicktype.io
Related
{
"message" : "success ",
"status" : "1",
"Result" : {
"name" : "abc",
"lastname" : null,
"middlename" : null,
"id" : 20431
}
}
i want to store result object into single userdefaults using model and how to retrieve it
From the docs here. Have you tried like this:
//convert the JSON to a raw String
if let rawString = json.rawString() {
userDefaults.set(rawString, forKey: "jsonData")
} else {
print("json.rawString is nil")
}
First create a model for this, using Codable protocol
struct MyJSON : Codable {
let message : String?
let status : String?
let result : JSONResult? // Don't use Result, a keyword in swift
}
struct JSONResult : Codable {
let name : String?
let lastname : String?
let middlename : String?
let id : Int?
}
Then Use the protocol to map the JSON, save the model in UserDefaults.
let jsonString =
"""
{
"message" : "success ",
"status" : "1",
"result" : {
"name" : "abc",
"lastname" : null,
"middlename" : null,
"id" : 20431
}
}
"""
let jsonData = Data(jsonString.utf8)
let data = try JSONDecoder().decode(MyJSON.self, from: jsonData)
// save model in userDefaults
func saveModel() {
if let encoded = try? JSONEncoder().encode(data) {
UserDefaults.standard.set(encoded, forKey: "MySavedValue")
}
}
//get the model
func getModel() -> MyJSON? {
guard let data = UserDefaults.standard.object(forKey: "MySavedValue") as? Data else {
return nil
}
return try? JSONDecoder().decode(MyJSON.self, from: data)
}
how to use
saveModel()
print(getModel()?.message) // print("Success")
This question already has answers here:
how to get array from dictionary in swift 3
(2 answers)
Closed 3 years ago.
I have following response to get Areas but I need an Individual array out of this with separator
{
"name" : "Abu Hail",
"city_id" : 1,
"pk" : 227,
"city" : "Dubai"
},
{
"name" : "Academic City",
"city_id" : 1,
"pk" : 184,
"city" : "Dubai"
},
{
"name" : "Al Barari",
"city_id" : 1,
"pk" : 185,
"city" : "Dubai"
},
{
"name" : "Al Barsha 1,2 & 3",
"city_id" : 1,
"pk" : 166,
"city" : "Dubai"
},
How can I make an array from name below out of this
["Abu Hail", "Academic City", "Al Barari", "Al Barsha 1,2 & 3"]
Following are my codes to get the above response
func getAreas(){
let headers: HTTPHeaders = [
"Authorization": "Token \(token!)",
"Accept": "application/json"
]
AF.request("\(staging.url)/api/addresses/areas/", method: .get, encoding: URLEncoding(), headers: headers).responseJSON { (response:DataResponse<Any>) in
switch response.result {
case let .success(value):
let json = JSON(value)
print("Areas Array: \(json)")
Create array using:
if let array = array as? [[String : Any]] {
let namesArray = array.compactMap { $0["name"] } as? [String]
}
It's better to create codable objects
// MARK: - AreaElement
struct AreaElement: Codable {
let name: String?
let cityID, pk: Int?
let city: String?
enum CodingKeys: String, CodingKey {
case name
case cityID = "city_id"
case pk, city
}
}
Now you can directly parse using JSONDecoder like
fileprivate func retrieve<T: Decodable>(data: Data, type: T.Type) -> T? {
let decoder = JSONDecoder()
do {
let model = try decoder.decode(type, from: data)
return model
} catch(let error) {
return nil
}
}
AF.request("\(staging.url)/api/addresses/areas/", method: .get, encoding: URLEncoding(), headers: headers).responseData { (response:DataResponse<Data>) in
if let data = response.data {
let models = self.retrieve(data: data, type: [Area].self)
// How you get name from model with one line
let names = models?.map {$0.name}
}
.......
Hopefully it will be helpful
I am trying to compare the studentId with the array of dictionaries which has multiple studentId's. I need to get the dictionary which matches with the particular StudentID..Can any one please suggest the perfect solution. I am new to swift.
"students" : [
{
"studentId" : "STUDENT123456789",
"middleName" : "Evangeline",
"firstName" : "Dia",
"rollNo" : "1001",
"studentClass" : {
"className" : "Grade 10",
"classId" : "CLASS123456789",
}
}
{
"studentId" : "STUDENT14354678960",
"middleName" : "Joseph",
"firstName" : "Parker",
"rollNo" : "1002",
"studentClass" : {
"className" : "Grade 10",
"classId" : "CLASS15468975467",
}
}
]
I have students array which is an array of dictionaries.Now I have to compare student Id with this existing array containing multiple studentID's. so when it matches with the student ID, I need to get that particular dictionary data.
For example, I have studentId as "STUDENT14354678960" so I need to get the data containing related to this Id..
Use first, it returns the first found object or nil
if let student = students.first(where: {$0["studentId"] as! String == "STUDENT123456789"}) {
print(student["firstName"])
} else {
print("not found")
}
It's highly recommended to use a custom struct or class for the student data for example
let jsonString = """
{"students" : [
{"studentId" : "STUDENT123456789", "middleName" : "Evangeline", "firstName" : "Dia", "rollNo" : "1001", "studentClass" : { "className" : "Grade 10", "classId" : "CLASS123456789"}},
{"studentId" : "STUDENT14354678960", "middleName" : "Joseph", "firstName" : "Parker", "rollNo" : "1002", "studentClass" : {"className" : "Grade 10", "classId" : "CLASS15468975467"}}
]}
"""
struct Root : Decodable {
let students : [Student]
}
struct Student : Decodable {
let studentId, middleName, firstName, rollNo : String
let studentClass : StudentClass
}
struct StudentClass : Decodable {
let className, classId : String
}
let data = Data(jsonString.utf8)
do {
let result = try JSONDecoder().decode(Root.self, from: data)
let students = result.students
if let student = students.first(where: {$0.studentId == "STUDENT123456789" }) {
print(student)
}
} catch {
print(error)
}
You can use where with a closure:
let search = students.first { (element) -> Bool in
if let dict = element as? [String:Any] {
return dict["studentId"] == yourID
}
}
So I'm creating an app that uses the Google Places API to gather a list of restaurants. Using the API provides me with a JSON file full of details about each location like lat, long, rating, priceLevel, openNow, photos, etc. Below is the code used to gather said JSON from my given parameters:
func performGoogleSearch(radius: Double, type: String, price: Int ) {
let location = locationManager.location?.coordinate
let url: URL = URL(string: "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=\(location?.latitude ?? 0),\(location?.longitude ?? 0)&radius=\(radius * 1609.34)&type=restaurant&maxprice=\(price)&key=AIzaSyBF0uwjr6BZc-Y-0kPsMBq2zNkl5EArioQ")!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
print(NSString(data: data!, encoding: String.Encoding.utf8.rawValue))
}
task.resume()
}
The data returned is a JSON like the following:
{
"html_attributions" : [],
"results" : [
{
"geometry" : {
"location" : {
"lat" : 37.7867167,
"lng" : -122.4111737
},
"viewport" : {
"northeast" : {
"lat" : 37.7881962302915,
"lng" : -122.4098846697085
},
"southwest" : {
"lat" : 37.7854982697085,
"lng" : -122.4125826302915
}
}
},
"icon" : "https://maps.gstatic.com/mapfiles/place_api/icons/lodging-71.png",
"id" : "3344890deedcb97b1c2d64814f92a02510ba39c8",
"name" : "Clift San Francisco",
"opening_hours" : {
"open_now" : false,
"weekday_text" : []
},
"photos" : [
{
"height" : 900,
"html_attributions" : [
"\u003ca href=\"https://maps.google.com/maps/contrib/114937580614387417622/photos\"\u003eClift San Francisco\u003c/a\u003e"
],
"photo_reference" : "CmRaAAAAwpWxfFJMJnK8G-LWJehCyUH5PFtepMF26XkZnXDRDo0wJMe-dAXLZ0zXGDmoEMi9n8YF5rYhgnr-EoDZFUawtiITYYocTJDAAjo1hw0sos4wVpfnx186o6pPgQWEv1f0EhDrydRti0bHEkhY4FNANV_KGhRmH8m7e6mO1sR2FlFxFuo5oSl00g",
"width" : 1155
}
],
"place_id" : "ChIJFUBxSY6AhYARwOaLV7TsLjw",
"price_level" : 4,
"rating" : 4.1,
"reference" : "CmRRAAAAA4IUvt3mHf2_QejiFA1acdgH2pg5h1_6GYDuVt-bzSwHqieSXmCAye5FRGJ0EjIM03WICU82MuKOiHor65j-e8rCDNEkltQnpoUX4AbCfRdybuqIPS5FxNsV_905or7BEhDNu3bKvzktrh2USu0zSNtoGhSkqf9WV1snRVufZ11kN6YgF961YQ",
"scope" : "GOOGLE",
"types" : [
"night_club",
"bar",
"lodging",
"restaurant",
"food",
"point_of_interest",
"establishment"
],
"vicinity" : "495 Geary Street, San Francisco"
},
{
"geometry" : {
"location" : {
"lat" : 37.78988329999999,
"lng" : -122.4091511
},
"viewport" : {
"northeast" : {
"lat" : 37.79135163029149,
"lng" : -122.4078268197085
},
"southwest" : {
"lat" : 37.78865366970849,
"lng" : -122.4105247802915
}
}
},
"icon" : "https://maps.gstatic.com/mapfiles/place_api/icons/lodging-71.png",
"id" : "547ceb15210b70b8734500183410bb10c644c395",
"name" : "Cornell Hotel De France",
"opening_hours" : {
"open_now" : true,
"weekday_text" : []
},
"photos" : [
{
"height" : 315,
"html_attributions" : [
"\u003ca href=\"https://maps.google.com/maps/contrib/114711934191765864568/photos\"\u003eCornell Hotel De France\u003c/a\u003e"
],
"photo_reference" : "CmRaAAAAJ3kTtFbeGT-8NWKbf9TPlN6gL6daO5zKq9DNZnzShZ-CcPUJnxMaVZybHZ0sGefM72WV01VcXr1AJWNKOSifZ63DIxxutKJ0ecqPUkM73LZLM-LO_eqsaWBRH8QN6PLYEhDykcPC3JAyDEDWpdiu3FP8GhRiJrTRNpnYQi1DDztzCRVKAM4N_A",
"width" : 851
}
],
"place_id" : "ChIJs6F3JYyAhYARDiVdBrmivCs",
"price_level" : 4,
"rating" : 4.2,
"reference" : "CmRRAAAAK05VMbTrE3cDxZreuM-Z0rbXcfdT4nflU0D17oCIwaF2RVbF85ch-1qKfRAGtMPxuuBvzw9sO-Y1rwRin-fEmzvgtiPsy8X_R2kfzh7rHX8iS8gJKc1QyTk2H4XU2O4hEhDMcIcjK5fWFvnGrJWxHgC6GhQAOkKXMCm7IjhOeOD__ZqzFlosmg",
"scope" : "GOOGLE",
"types" : [
"clothing_store",
"store",
"lodging",
"restaurant",
"food",
"point_of_interest",
"establishment"
],
"vicinity" : "715 Bush Street, San Francisco"
}
],
"status" : "OK"
}
I have an object called "Location" that hopes to take the JSON as a parameter to fill in its respective values. I would like to get to the point where I can take this JSON and turn it into an array of my "Location" struct populated with one "Location" for each restaurant returned in the Google Places API JSON.
Here is the "Location" struct:
import Foundation
struct Location: Codable {
var lat: Double
var long: Double
var icon: String?
var id: String?
var name: String
var openNow: Bool?
var photos: [String : Any]?
var placeID: String?
var priceLevel: Int?
var rating: Double?
var types: [String]?
init?(json: [String: Any]) {
guard let lat = json["lat"] as? Double,
let long = json["lng"] as? Double,
let icon = json["icon"] as? String,
let id = json["id"] as? String,
let name = json["name"] as? String,
let openNow = json["open_now"] as? Bool,
let photos = json["photos"] as? [String : Any],
let placeID = json ["place_id"] as? String,
let priceLevel = json["price_level"] as? Int,
let rating = json["rating"] as? Double,
let types = json["types"] as? [String]? else {
return nil
}
self.lat = lat
self.long = long
self.icon = icon
self.id = id
self.name = name
self.openNow = openNow
self.photos = photos
self.placeID = placeID
self.priceLevel = priceLevel
self.rating = rating
self.types = types
}
}
This struct is a start but is clearly lacking as I do not know how to go about taking the data from the JSON to make an array of this "Location" struct. Any guidance would be appreciated.
You can use JSONDecoder
let decoder = JSONDecoder()
do {
let locations = try decoder.decode([Location].self, from: yourJson)
print(locations)
} catch {
print(error.localizedDescription)
}
Also you can nest structs to represent your data which you're probably going to have to do. Have a look at "More Complex Nested Response" on this guide to JSON parsing
I eventually changed my "Location" struct to
Not be codable
Take each property as a parameter as opposed to taking the whole JSON dictionary as the parameter
In the "performGoogleSearch()" function, I essentially had to keep converting values of the dictionary into dictionaries themselves in order to reach deeper into the file. I then used each value I could get out of the JSON file and used them to create an object of my class. I then appended each object to my array of results.
func performGoogleSearch(radius: Double, type: String, price: Int ) {
let location = locationManager.location?.coordinate
let url: URL = URL(string: "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=\(location?.latitude ?? 0),\(location?.longitude ?? 0)&radius=\(radius * 1609.34)&type=restaurant&maxprice=\(price)&key=AIzaSyBF0uwjr6BZc-Y-0kPsMBq2zNkl5EArioQ")!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
let jsonObject = try? JSONSerialization.jsonObject(with: data! as Data, options: [])
if let jsonArray = jsonObject as? [String: Any] {
if let results = jsonArray["results"] as! [Any]?{
for result in results {
if let locationDictionary = result as? [String : Any] {
let geometry = locationDictionary["geometry"]! as! [String : Any]
let location = geometry["location"]! as! [String : Any]
let lat = location["lat"]
let long = location["lng"]
let openingHours = locationDictionary["opening_hours"] as? [String : Any]
let openNow = openingHours?["open_now"]
let photos = locationDictionary["photos"] as? [[String : Any]]
let newLocation = Location(lat: lat as! Double, long: long as! Double, id: locationDictionary["id"] as? String, name: locationDictionary["name"] as! String, openNow: openNow as? Int, photos: photos, placeID: locationDictionary["place_id"] as? String, priceLevel: locationDictionary["price_level"] as? Int, rating: locationDictionary["rating"] as? Double, types: locationDictionary["types"] as? [String])
googleResults.append(newLocation!)
}
}
print("Results: \(googleResults.count)")
let randomInt = Int(arc4random_uniform(UInt32(googleResults.count)))
print("RandomInt: \(randomInt)")
if googleResults.count != 0 {
self.googleResult = googleResults[randomInt]
self.annotation = MapBoxAnnotation(coordinate: CLLocationCoordinate2D(latitude: (self.self.googleResult?.lat)!, longitude: (self.self.googleResult?.long)!), title: self.googleResult?.name, subtitle: nil)
}
}
}
DispatchQueue.main.async {
self.animateResultView()
}
}
task.resume()
Location struct:
struct Location {
var lat: Double
var long: Double
var id: String?
var name: String
var openNow: Int?
var photos: [[String : Any]]?
var placeID: String?
var priceLevel: Int?
var rating: Double?
var types: [String]?
init?(lat: Double, long: Double, id: String?, name: String, openNow: Int?, photos: [[String : Any]]?, placeID: String?, priceLevel: Int?, rating: Double?, types: [String]?) {
self.lat = lat
self.long = long
self.id = id
self.name = name
self.openNow = openNow
self.photos = photos
self.placeID = placeID
self.priceLevel = priceLevel
self.rating = rating
self.types = types
}
}
I'm following https://developers.google.com/places/web-service/details this doc to add all the information about a place, and for example to add "geometry"
"geometry" : {
"location" : {
"lat" : -33.866651,
"lng" : 151.195827
},
i created this function in my class that work well
private let geometryKey = "geometry"
private let locationKey = "location"
private let latitudeKey = "lat"
private let longitudeKey = "lng"
class EClass: NSObject {
var location: CLLocationCoordinate2D?
init(placeInfo:[String: Any]) {
placeId = placeInfo["place_id"] as! String
// coordinates
if let g = placeInfo[geometryKey] as? [String:Any] {
if let l = g[locationKey] as? [String:Double] {
if let lat = l[latitudeKey], let lng = l[longitudeKey] {
location = CLLocationCoordinate2D.init(latitude: lat, longitude: lng)
}
}
}
}
but but i'm having difficulty adding "reviews"
"reviews" : [
{
"author_name" : "Robert Ardill",
"author_url" : "https://www.google.com/maps/contrib/106422854611155436041/reviews",
"language" : "en",
"profile_photo_url" : "https://lh3.googleusercontent.com/-T47KxWuAoJU/AAAAAAAAAAI/AAAAAAAAAZo/BDmyI12BZAs/s128-c0x00000000-cc-rp-mo-ba1/photo.jpg",
"rating" : 5,
"relative_time_description" : "a month ago",
"text" : "Awesome offices. Great facilities, location and views. Staff are great hosts",
"time" : 1491144016
}
],
i tried to follow the same concept of the function i created for geometry like this
if let t = place.details?["reviews"] as? [String:Any] {
if let n = t["author_name"], let m = t["text"] {
Mylabel.text = "\(t)"
}
but is not working, i also tried to add a breakpoint and only the first line enters. What can i do? How can i create a build to show the review with a label or anything i need?
Take advantage of Codable in Swift 4. You can simply convert your JSON into a specific struct. e.g. Based on your JSON:
let json = """
{
"reviews" : [
{
"author_name" : "Robert Ardill",
"author_url" : "https://www.google.com/maps/contrib/106422854611155436041/reviews",
"language" : "en",
"profile_photo_url" : "https://lh3.googleusercontent.com/-T47KxWuAoJU/AAAAAAAAAAI/AAAAAAAAAZo/BDmyI12BZAs/s128-c0x00000000-cc-rp-mo-ba1/photo.jpg",
"rating" : 5,
"relative_time_description" : "a month ago",
"text" : "Awesome offices. Great facilities, location and views. Staff are great hosts",
"time" : 1491144016
}
]
}
"""
You can convert it into a Response struct using the following code:
struct Response: Codable {
struct Review: Codable, CustomStringConvertible {
let text: String
let authorName: String
var description: String {
return "Review text: \(text) authorName: \(authorName)"
}
enum CodingKeys: String, CodingKey {
case text
case authorName = "author_name"
}
}
let reviews: [Review]
}
do {
if let data = json.data(using: .utf8) {
let decoder = JSONDecoder()
let decoded = try decoder.decode(Response.self, from: data)
print(decoded.reviews)
} else {
print("data is not available")
}
} catch (let e) {
print(e)
}
In your code t is not a Dictionary it is an Array instead. So try doing something like this. Rest of that you can change as per your logic.
if let t = place.details?["reviews"] as? [String:Any] {
for dic in t {
if let n = dic["author_name"], let m = dic["text"] {
Mylabel.text = "\(t)"
}
}
}
Yeah, but You can also try to make it like that:
struct reviews: Codable{
var reviews: [review]?
}
struct review: Codable{
var author_name: String?
var author_url: String?
var language: String?
var profile_photo_url: String?
var rating: Int?
var relative_time_description: String?
var text: String?
var time: Int?
}
And then:
if let dict = place.details?["reviews"] as? [String: Any],
let dataToDecode = dict.data(using: .utf8){
do{
let decodedReviews = try JSONDecoder().decode(reviews.self, from: dataToDecode)
// here you have decoded reviews in array
}catch let err{
print(err)
}
}