I new to Alamofire, I was testing out some API. I came across foreign exchange rates. So the JSON file is like this
["base": CAD, "date": 2016-12-01, "rates": {
AUD = "1.0097";
BGN = "1.3735";
BRL = "2.57";
CHF = "0.7559";
CNY = "5.1388";
CZK = "19.004";
DKK = "5.2248";
EUR = "0.70225";
GBP = "0.59058";
HKD = "5.7881";
HRK = "5.2985";
HUF = "220.48";
IDR = 10108;
ILS = "2.8607";
INR = "51.009";
JPY = "85.246";
KRW = "871.9400000000001";
MXN = "15.403";
MYR = "3.331";
NOK = "6.2941";
NZD = "1.0539";
PHP = "37.102";
PLN = "3.1374";
RON = "3.1631";
RUB = "47.591";
SEK = "6.8775";
SGD = "1.0657";
THB = "26.616";
TRY = "2.6006";
USD = "0.7462800000000001";
ZAR = "10.504";}]
typealias JSONStandard = [String: AnyObject]
func parseData(JSONData:Data) {
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONStandard
if let rates = readableJSON["rates"] as? JSONStandard{
for i in 0..<rates.count {
let rate = rates[i] as! //Here
}
print(rates)
}
print(readableJSON)
} catch {
print(error)
}
}
I was able to get side "rates" but I don't get how I would parse all the data inside the "rates". I thought I would have to save it inside a dictionary. very confused Thanks
As you can see it's a double value in String, so you need to convert AnyObject to String first, then convert it to Double. You can do it like this (Tested in Swift playground) :
import Foundation
typealias JSONStandard = [String: AnyObject]
func parseData(JSONData:Data) {
do {
guard let readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as? JSONStandard,
let ratesJSON = readableJSON["rates"] as? JSONStandard
else { return }
print("Readable JSON :")
print(readableJSON)
let rates = ratesJSON.flatMap({ (key, value) -> ([String: Double]) in
guard let value = value as? String, let convertedValue = Double(value) else { return [:] }
return [key: convertedValue]
})
print("Rates :")
print(rates)
} catch {
print(error)
}
}
let jsonString = "{\"base\": \"CAD\", \"date\": \"2016-12-01\", \"rates\": { \"AUD\": \"1.0097\", \"BGN\": \"1.3735\", \"BRL\": \"2.57\"}}"
let jsonData = jsonString.data(using: String.Encoding.utf8)!
parseData(JSONData: jsonData)
Result :
Readable JSON :
["base": CAD, "date": 2016-12-01, "rates": {
AUD = "1.0097";
BGN = "1.3735";
BRL = "2.57";
}]
Rates :
[("BGN", 1.3734999999999999), ("AUD", 1.0097), ("BRL", 2.5699999999999998)]
You have to save it into an array of Double:
var yourArray = [Double]()
for i in 0..<rates.count {
let rate = rates[i] as! Double
print(rate)
yourArray.append(rate)
}
print(yourArray.description)
Related
I am trying to save json data which is present in my app bundle. But instead of saving all data it is saving only one data
func getDignosysListFromJson() {
let coreData = CoreDataStack()
let managedObjectContext = coreData.persistentContainer.viewContext
let dignose = Dignose(context: managedObjectContext)
let jsonPath = Bundle.main.path(forResource: "dignosys", ofType: "json")
let jsonUrl = URL(fileURLWithPath: jsonPath!)
do {
let data = try Data(contentsOf: jsonUrl)
let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
if let newResult = jsonResult as? Array<Dictionary<String, Any>>{
for i in newResult{
let newName = i["dx description"] as! String
print(newName)
dignose.name = newName
dignose.date = "29 Dec 2020"
}
coreData.saveContext()
}
} catch {
print("")
}
}
My json structure is:-
[
{"dx type":"what is foot issue","dx description":"Hereditary motor and sensory neuropathy"},
{"dx type":"what is foot issue","dx description":"Multiple sclerosis"},
{"dx type":"use as secondary when only have issue one side","dx description":"gait instabilityā€¯}
]
Move the line
let dignose = Dignose(context: managedObjectContext)
into the loop
for i in newResult {
let dignose = Dignose(context: managedObjectContext)
let newName = i["dx description"] as! String
print(newName)
dignose.name = newName
dignose.date = "29 Dec 2020"
}
to get a new instance in each iteration.
The code contains a few questionable practices. I recommend this
func getDignosysListFromJson() {
let coreData = CoreDataStack()
let managedObjectContext = coreData.persistentContainer.viewContext
let jsonUrl = Bundle.main.url(forResource: "dignosys", withExtension: "json")!
do {
let data = try Data(contentsOf: jsonUrl)
if let jsonResult = try JSONSerialization.jsonObject(with: data) as? [[String:Any]] {
for anItem in jsonResult {
let dignose = Dignose(context: managedObjectContext)
let newName = anItem["dx description"] as! String
print(newName)
dignose.name = newName
dignose.date = "29 Dec 2020"
}
coreData.saveContext()
}
} catch {
print(error)
}
}
I am working on swift json Parsing where i am recieving json Data from Rest API for eg:
{"baseUrl":"http:\/\/localhost:9010\/",
"pluginOptions":{"values":[{"StartSyncTime":"2020-10-06 17:22:34","uuid":"977a5d03-2cdf-4008-87e6-01594e4369ef","LastSyncTime":"2020-10-06",
"MessageWrapper":{"Routing":"OriginSession","SourceSystem":"Mobile","MessageId":"51152ccd-32c6-475b-86a6-a2c883d551f5",
"UserID":"77ee794e-433d-4b93-bcaa-53408ede50fd","TenantID":"null","TenantName":"visurtest","Payload":"{}",
"DataType":"SQLLiteDDLAsync","MessageKind":"READ"}}],
"database":"structionDB","encrypted":false,"mode":"no-encryption"}}
I am getting as type [String:Any?] from rest api in below code
var pluginOptions : [String: Any]? = call.getObject("pluginOptions")
pluginOptions?[MessageWrapperKeys.DataType] = [DataTypes.SQLLiteDDLAsync]
pluginOptions?[MessageWrapperKeys.MessageKind] = [MessageKinds.READ]
pluginOptions?[MessageWrapperKeys.Payload] = ["{}"]
from above Json Response i need to extract MessageWrapper Dictionary like below
{"Routing":"OriginSession","SourceSystem":"VisurMobile","MessageId":"51152ccd-32c6-475b-86a6-a2c883d551f5",
"UserID":"77ee794e-433d-4b93-bcaa-53408ede50fd","TenantID":"null","TenantName":"visurtest","Payload":"{}",
"DataType":"SQLLiteDDLAsync","MessageKind":"READ"}
where above last 3 key vale i have added from code,Now i have to send Rest Api Call with above request but i did not able to figure it out how i will extraxt MessageWrapper Keys and append above 3 Key Values so that i get final jsonString Request like
{"Routing":"OriginSession","SourceSystem":"Mobile","MessageId":"05086b82-3623-492b-926a-d3bb8d01aa52","UserID":"77ee794e-433d-4b93-bcaa-53408ede50fd","TenantID":"null","TenantName":"test","Payload":"{}","DataType":"SQLLiteDDLAsync","MessageKind":"READ"}
below code i have triyed but not able to access
func readTableFromBackend(_ call: CAPPluginCall) -> Observable<String>{
var swrapper: [[String: Any]] = [[:]]
var pluginOptions : [String: Any]? = call.getObject("pluginOptions")
let json = JSON(pluginOptions)
var arrayNames = json["values"].arrayValue.map {$0["MessageWrapper"].string}
for arrayvalues in json["values"].arrayValue{
for arrayvalues in json["MessageWrapper"].arrayValue{
var string = arrayvalues["UserID"].string
}
var string = arrayvalues["MessageWrapper"].string
print(string)
}
pluginOptions?[MessageWrapperKeys.DataType] = [DataTypes.SQLLiteDDLAsync]
pluginOptions?[MessageWrapperKeys.MessageKind] = [MessageKinds.READ]
pluginOptions?[MessageWrapperKeys.Payload] = ["{}"]
var values = pluginOptions?["values"]
var modes = pluginOptions?["mode"]
for (key,value)in pluginOptions ?? ["":""]{
print("\(key) -> \(value)")
}
var finajsonstring: String = ""
var pluginOptions1: [String:Any] = [MessageWrapperKeys.DataType:DataTypes.SQLLiteDDLAsync, MessageWrapperKeys.MessageKind:MessageKinds.READ,MessageWrapperKeys.Payload: "{}"]
swrapper.append(pluginOptions ?? ["":""])
swrapper.append(pluginOptions1 )
let apidata = PullBackendData()
let plugindata = PluginCallParameterOptions()
var url: String? = call.getString("baseUrl")
// let payload = swrapper
let address = plugindata.getApiUrl(controllerName: Controllers.DataSync, baseUrl: url ?? "")
let jsonData = try? JSONSerialization.data(withJSONObject: pluginOptions)
guard let jsonString = String(data : jsonData!, encoding: .utf8
) else { return Observable.just("Error")}
let data = Data(jsonString.utf8)
do{
let newdata : NSDictionary = try JSONSerialization.jsonObject(with: data, options: []) as! NSDictionary
}
if((newdata.value(forKey: "values")) != nil){
let info : NSArray = newdata.value(forKey: "values") as! NSArray
let info1 : NSArray = info.value(forKey: "MessageWrapper") as! NSArray
var wrapperarray: [[String:Any]] = [[String:Any]]()
wrapperarray = newdata.value(forKey: "values") as! [[String:Any]]
wrapperarray.append(pluginOptions1)
let jsonData: NSData = try JSONSerialization.data(withJSONObject: info1, options: []) as NSData
let jsonData2: NSData = try JSONSerialization.data(withJSONObject: wrapperarray, options: []) as NSData
do {
var jsonstring = try NSString(data: jsonData as Data, encoding: String.Encoding.utf8.rawValue)! as String
var jsonstring2 = NSString(data: jsonData2 as Data, encoding: String.Encoding.utf8.rawValue)! as String
//getting final string and sending to rest api
finajsonstring = jsonstring2 as String
}catch {
print("error")
}
}
} catch let error as NSError{
print(error)
}
let response = apidata.post(_for: address, bodyData: finajsonstring)
return Observable.from(optional: response)
}
I have successfully parsed JSON for:
birthday = "04/10/1986";
id = 202038339983;
location = {
city = Jupiter;
country = "United States";
state = FL;
};
My question is when part of the JSON is:
submissions = {
data = (
{
"created_time" = "2018-02-16T05:11:56+0000";
id = "131448394823824_167398094382256";
viewer = "Any random string and/or emojis";
},
{
"created_time" = "2018-02-14T23:36:41+0000";
id = "809809871824_8908987486899";
message = "vday \Ud83d\Udda4\U2665\Ufe0f";
});}
How am I supposed to access created_time, id, viewer, and message?
I have been able to print the whole submissions JSON response to the console with this code :
guard let jsonD = responseFromServer as? [String : Any] else {return}
let subs1 = (jsonD["submissions"] as? [String : Any])
let accessSubs1 = theSubs1
guard let parsedPost = theSubs1 else {
return
}
My console will display:
["data": <__NSArrayI 0x6040001a86c0>(
{
"created_time" = "2018-02-16T05:11:56+0000";
id = "131448394823824_167398094382256";
viewer = "Any random string and/or emojis";
},
{
"created_time" = "2018-02-14T23:36:41+0000";
id = "809809871824_8908987486899";
message = "vday \Ud83d\Udda4\U2665\Ufe0f";
})]
My question is how should I parse the JSON so I can access the created_time inside submissions?
Here is the HTTP Request:
struct XClass: RequestProtocol {
var Path = "/User"
var parameters: [String : Any]? = ["stuff": "id, birthday, location, submissions"]
var aToken = aToken.current
var httpMethod: RequestHTTPMethod = .GET
var apiVersion: APIVersion = .defaultVersion
struct Response: ResponseProtocol {
var id = String()
var birthday = String()
var city = String()
var state = String()
var country = String()
var viewSubs = [String : Any]()
init(XResponse: Any?) {
guard let jsonD = XResponse as? [String : Any] else {return}
id = (jsonD["id"] as? String)!
birthday = (jsonD["birthday"] as? String)!
let XArr = (jsonD["location"] as? [String : String])
city = XArr!["city"]!
country = XArr!["country"]!
state = XArr!["state"]!
let subs1 = (jsonD["submissions"] as? [String : Any])
let accessSubs1 = theSubs1
guard let parsedPost = theSubs1 else {
return
}
viewSubs = theSubs1
}}}
func getXData(){
let connection = RequestConnection()
connection.add(XClass()) { response, result in
switch result {
case .success(let response):
print("Request Succeeded: \(response)\n\n\n")
case .failed(let error):
print("Request Failed: \(error)")
}}
connection.start()
}
Create a struct
struct Data: Decodable {
var created_time : String
var id : String
var viewer : String
}
call to the api url from URLSession
guard let url = URL(string: "your api url")
URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error.localizedDescription)
} else {
guard let data = data else {return}
var data: [Data]() = JSONDecoder().decode(Data.self, data)
for dat in data{
print(dat.created_time)
print(dat.id)
print(dat.viewer)
}
}
If you are not using Decodable from Swift 4, or still in Swift 3,
then you can specify that the data in "submissions" is an array of dictionaries (double brackets) then you can iterate that.
Change
let subs1 = (jsonD["submissions"] as? [String : Any])
To
let subs1 = (jsonD["submissions"] as? [[String : Any]])
for sub in subs1 {
let time = sub["created_time "] as? [String : Any]
...
}
1. This is the response String
{"error_msg": null,"applicationStateJson": {"notifications_size": "0","dfilterlogin": 1,"loginstype": null,"email_status": "0","address_status": "0","defaultfiltername": "hyderabad","login_status": "1","defaultfilterid": 145,"profile_id": null,"freelancer": "Y","otp_status": "1","notifications": []},"status": null}
2. Below one is the perfect JSONObject, I get it to using JSONLint
{
"error_msg": null,
"applicationStateJson": {
"notifications_size": "0",
"dfilterlogin": 1,
"loginstype": null,
"email_status": "0",
"address_status": "0",
"defaultfiltername": "hyderabad",
"login_status": "1",
"defaultfilterid": 145,
"profile_id": null,
"freelancer": "Y",
"otp_status": "1",
"notifications": []
},
"status": null
}
3. When I try the below code in Swift 3
let json1 = try? JSONSerialization.jsonObject(with: data, options: [])
if let object = json1 as? [String: Any]{
if let applicationState = object["applicationStateJson"] as? [String: Any]{
print("applicationState \(applicationState)")
}
}
4. I got JSONObject but it's not a proper JSONObject
(because the commas are changed into semicolon, null values are changed into "< null >" and then empty array [] changed into ())
Optional({
applicationStateJson = {
"address_status" = 0;
defaultfilterid = 145;
defaultfiltername = hyderabad;
dfilterlogin = 1;
"email_status" = 0;
freelancer = Y;
"login_status" = 1;
loginstype = "<null>";
notifications = (
);
"notifications_size" = 0;
"otp_status" = 1;
"profile_id" = "<null>";
};
"error_msg" = "<null>";
status = "<null>";
})
I want the JSONObject like the step 2, any help?
To read and use a JSON response in Swift does not require you to convert the JSON object back to JSON just to get a particular part. Once you have the data loaded into a Swift type you can work directly with it to get the parts you need.
So the long way which explains my point better...
let jsonData = jsonString.data(using: .utf8)!
let json1 = try? JSONSerialization.jsonObject(with: jsonData, options: [])
if let object = json1 as? [String: Any]{
if let applicationState = object["applicationStateJson"] as? [String: Any]{
print("applicationState \(applicationState)")
if let addressStatus = applicationState["address_status"] as? String {
print(addressStatus)
}
}
}
The Swift 4 way of doing this with the Codable Protocol
let jsonString = "{\"error_msg\": null,\"applicationStateJson\": {\"notifications_size\": \"0\",\"dfilterlogin\": 1,\"loginstype\": null,\"email_status\": \"0\",\"address_status\": \"0\",\"defaultfiltername\": \"hyderabad\",\"login_status\": \"1\",\"defaultfilterid\": 145,\"profile_id\": null,\"freelancer\": \"Y\",\"otp_status\": \"1\",\"notifications\": []},\"status\": null}"
struct ApplicationState: Codable {
let notificationsSize: String
let dFilterLogin: Int
let loginsType: String?
let emailStatus: String
let addressStatus: String
enum CodingKeys : String, CodingKey {
case notificationsSize = "notifications_size"
case dFilterLogin = "dfilterlogin"
case addressStatus = "address_status"
case loginsType = "loginstype"
case emailStatus = "email_status"
}
}
struct ApplicationStateResponse: Codable {
let errorMsg: String?
let applicationState: ApplicationState
enum CodingKeys : String, CodingKey {
case errorMsg = "error_msg"
case applicationState = "applicationStateJson"
}
}
let jsonData = jsonString.data(using: .utf8)!
let decoder = JSONDecoder()
let response = try! decoder.decode(ApplicationStateResponse.self, from: jsonData)
let appState = response.applicationState
print(appState.addressStatus)
Both of these print 0 for the address status as expected. one is much easier to work with than the other though.
This article which explains the codable protocol a bit more would be a good read.
Convert Swift Dictionary object to JSON string,
if let theJSONData = try? JSONSerialization.data(withJSONObject: applicationState, options: .prettyPrinted),
let theJSONText = String(data: theJSONData, encoding: String.Encoding.ascii) {
print("JSON string = \n\(theJSONText)")
}
I'm trying to build a login function (POST method) and the resultant is a JSON with user details and few other details. I have created a class with all the fields I need to use from the result of POST call. But I'm facing an issue with deserialzing the json to the object of the class. Can some one help me with this. (I have seen similar questions on SO and tried solving using the solution. I have tried converting the json to string and then to swift object using var UserDetails = UserDetails(json:jsonString)
)
My code:
class UserDetails {
let token:String
let agent_id: Int
let user_id:Int
let company_id:Int
let affliate_Id:Int
let role_id:Int
let username: String
let surname:String
let lastname:String
init(token:String,agent_id: Int,user_id:Int,company_id:Int,affliate_Id:Int,role_id:Int,username: String,surname:String,lastname:String) {
self.token = token;
self.agent_id = agent_id;
self.user_id = user_id;
self.company_id = company_id;
self.affliate_Id = affliate_Id;
self.role_id = role_id;
self.username = username;
self.surname = surname;
self.lastname = lastname;
} }
My controller class:
let task = session.dataTask(with: request as URLRequest) { data, response, error in
guard data != nil else {
print("no data found: \(error)")
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary {
NSLog("Login SUCCESS");
let prefs:UserDefaults = UserDefaults.standard
prefs.set(username, forKey: "USERNAME")
prefs.set(udid, forKey: "UDID")
prefs.synchronize()
print("Response: \(json)")
//var jsonString = NSString(data: json, encoding: String.Encoding.utf8)! as String
//when I tried to do the above statement, an error is thrown. Cannot convert value of type NSDictionary to expected argument type Data
//var person:UserDetails = UserDetails(json: jsonString)
self.dismiss(animated: true, completion: nil)
} else {
let jsonStr = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)// No error thrown, but not NSDictionary
print("Error could not parse JSON: \(jsonStr)")
}
} catch let parseError {
print(parseError)// Log the error thrown by `JSONObjectWithData`
let jsonStr = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("Error could not parse JSON: '\(jsonStr)'")
}
}
task.resume()
JSON Response:
{
"user": {
"token": "ABCDEFGHI",
"agent_id": 0,
"user_id": 151,
"company_id": 1,
"affiliate_Id": 0,
"role_id": 1,
"username": "testman1",
"surname": "Test",
"lastname": "man",
},
"menu": [
{ .....
Can someone help me in solving this. Tia
You should avoid using Foundation classes (NSDictionary etc) and use Swift types.
I also suggest you add a failable initialiser to your UserDetails class that accepts a dictionary:
class UserDetails {
let token: String
let agentId: Int
let userId: Int
let companyId: Int
let affliateId: Int
let roleId: Int
let username: String
let surname: String
let lastname: String
init?(dictionary: [String:Any]) {
guard let token = dictionary["token"] as? String,
let agentId = dictionary["agent_id"] as? Int,
let userId = dictionary["user_id"] as? Int,
... // And so on
else {
return nil
}
self.token = token;
self.agentId = agentId;
self.userId = userId;
self.companyId = companyId;
self.affliateId = affliateId;
self.roleId = roleId;
self.username = username;
self.surname = surname;
self.lastname = lastname;
}
}
and in your completion block:
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:Any] {
if let userDict = json["user"] as [String:Any] {
guard let userObject = UserDetails(dictionary:userDict) else {
print("Failed to create user from dictionary")
return
}
// Do something with userObject
}
}
} catch let parseError {
I also took the liberty of removing the _ from your properties because _ are icky
First of all you need to use Swift native Dictionary instead of NSDictionary also batter if you define your init method of UserDetails with single parameter of type [String: Any].
class UserDetails {
var token:String = ""
var agent_id: Int = 0
var user_id:Int = 0
var company_id:Int = 0
var affliate_Id:Int = 0
var role_id:Int = 0
var username: String = ""
var surname:String = ""
var lastname:String = ""
init(userDic: [String: Any]) {
if let token = user["token"] as? String, let agent_id = user["agent_id"] as? Int,
let user_id = user["user_id"] as? Int, let company_id = user["company_id"] as? Int,
let affliate_Id = user["affliate_Id"] as? Int, let role_id = user["role_id"] as? Int,
let username = user["username"] as? String, let surname = user["surname"] as? String,
let lastname = user["lastname"] as? String {
self.token = token;
self.agent_id = agent_id;
self.user_id = user_id;
self.company_id = company_id;
self.affliate_Id = affliate_Id;
self.role_id = role_id;
self.username = username;
self.surname = surname;
self.lastname = lastname;
}
}
}
Now simply call this init method from your json response like this.
if let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any], let userDic = json["user"] as? [String: Any]{
let userDetails = UserDetails(userDic: userDic)
}