Parsing string json in swift 3 - json

I have a json saved in String format and I´m trying to use:
let json = "{'result':[{'name':'Bob','age':'27'}]}";
Using JSONSerialization comes error about Cannot invoke jsonOject with an argument...
if let json = try JSONSerialization.jsonObject(with: json) as? [String: Any],
let array = json["result"] as? [[String: Any]] {
for item in array {
if let name = item["name"] as? String {
if name == "Bob" {
self.age = Int((item["age"] as? String)!)!
}
}
}
}
I tryed to use this solution but with no success.

Please look at the declaration of jsonObject(with) by ⌥-click on the symbol.
The first parameter is of type Data so you have to convert String to Data.
A major issue is that the JSON is not formatted correctly. The string indicators must be double quotes.
let json = "{\"result\":[{\"name\":\"Bob\",\"age\":27}]}"
let jsonData = json.data(using: .utf8)
do {
if let result = try JSONSerialization.jsonObject(with: jsonData!) as? [String: Any],
...
self.age = item["age"] as! Int

Related

How to parse string in swift

My json is like this:
"billerdetails": [
{
"id": "1",
"bname": "ACT Fibernet",
"bcustomerparms": "[{\"paramName\":\"Account Number/User Name\",\"dataType\":\"ALPHANUMERIC\",\"optional\":\"false\",\"minLength\":\"1\",\"maxLength\":\"50\"}]",
"breponseParams": "[{\"amtBreakupList\":[{\"amtBreakup\":\"BASE_BILL_AMOUNT\"}]}]",
......
Here i am able to get bcustomerparms. but here i need bcustomerparms: paramName value like (Account Number/User Name) in one virable.. for that i have written code like below but i am unable to get Account Number/User Name in vairable.
Please help me in below code:
do{
let jsonObj = try JSONSerialization.jsonObject(with: respData, options: .allowFragments) as! [String: Any]
//print("the all make payment json is \(jsonObj)")
let billerdetailsArray = jsonObj["billerdetails"] as! [[String: Any]]
for billerdetail in billerdetailsArray {
self.categoryName = billerdetail["bname"] as? String
var customrParams = billerdetail["bcustomerparms"]
print("biller customrParams \(customrParams)")
}
// here i am getting bcustomerparms
biller customrParams Optional([{"paramName":"Connection ID","dataType":"ALPHANUMERIC","optional":"false","minLength":"8","maxLength":"10"}])
but here i want only paramName value how to get that value. please help me in the above code.
bcustomerparms value is a string not an array of dictionaries , You can try
let customrParams = billerdetail["bcustomerparms"] as! String
let res = try JSONSerialization.jsonObject(with:Data(customrParams.utf8)) as! [[String: Any]]
for item in res {
print(item["paramName"])
}

Not able to decode a json answer in swift

I try to decode a json answer from a camera. But the camera is answering keys with null (this depends on the camera type).
The result string looks like that:
let string = "{\"id\":1,\"result\":[{\"names\":[\"getAvailableApiList\",\"getShootMode\",\"getSupportedShootMode\",\"getAvailableShootMode\",\"setFlashMode\",\"getFlashMode\",\"getSupportedFlashMode\",\"getAvailableFlashMode\",\"setSelfTimer\",\"getSelfTimer\",\"getSupportedSelfTimer\",\"getAvailableSelfTimer\",\"getSupportedMovieQuality\",\"startLiveview\",\"stopLiveview\",\"actTakePicture\",\"startMovieRec\",\"stopMovieRec\",\"awaitTakePicture\",\"getExposureMode\",\"getSupportedExposureMode\",\"getAvailableExposureMode\",\"setExposureCompensation\",\"getExposureCompensation\",\"getSupportedExposureCompensation\",\"getAvailableExposureCompensation\",\"setFNumber\",\"getFNumber\",\"getSupportedFNumber\",\"getAvailableFNumber\",\"setWhiteBalance\",\"getWhiteBalance\",\"getSupportedWhiteBalance\",\"getAvailableWhiteBalance\",\"getShutterSpeed\",\"getSupportedShutterSpeed\",\"getAvailableShutterSpeed\",\"setIsoSpeedRate\",\"getIsoSpeedRate\",\"getSupportedIsoSpeedRate\",\"getAvailableIsoSpeedRate\",\"actHalfPressShutter\",\"cancelHalfPressShutter\",\"getSupportedProgramShift\",\"getSupportedMovieFileFormat\",\"setContShootingMode\",\"getContShootingMode\",\"getSupportedContShootingMode\",\"getAvailableContShootingMode\",\"setWirelessFlashSetting\",\"getWirelessFlashSetting\",\"getSupportedWirelessFlashSetting\",\"getAvailableWirelessFlashSetting\",\"getApplicationInfo\",\"getEvent\",\"getTemporarilyUnavailableApiList\"],\"type\":\"availableApiList\"},{\"cameraStatus\":\"IDLE\",\"type\":\"cameraStatus\"},null,{\"liveviewStatus\":true,\"type\":\"liveviewStatus\"},null,[],[{\"continuousError\":\"Overheating Warning\",\"isContinued\":false,\"type\":\"continuousError\"},{\"continuousError\":\"Remote Control Not Currently Available\",\"isContinued\":false,\"type\":\"continuousdfError\"}],null,null,null,[],null,null,null,null,null,null,null,{\"currentExposureMode\":\"Aperture\",\"exposureModeCandidates\":[],\"type\":\"exposureMode\"},null,{\"currentSelfTimer\":0,\"selfTimerCandidates\":[0,2,5,10],\"type\":\"selfTimer\"},{\"currentShootMode\":\"still\",\"shootModeCandidates\":[\"still\",\"movie\",\"slow and quick\"],\"type\":\"shootMode\"},null,null,null,{\"currentExposureCompensation\":0,\"maxExposureCompensation\":15,\"minExposureCompensation\":-15,\"stepIndexOfExposureCompensation\":1,\"type\":\"exposureCompensation\"},{\"currentFlashMode\":\"on\",\"flashModeCandidates\":[\"on\",\"rearSync\",\"slowSync\"],\"type\":\"flashMode\"},{\"currentFNumber\":\"3.5\",\"fNumberCandidates\":[\"3.5\",\"4.0\",\"4.5\",\"5.0\",\"5.6\",\"6.3\",\"7.1\",\"8.0\",\"9.0\",\"10\",\"11\",\"13\",\"14\",\"16\",\"18\",\"20\",\"22\"],\"type\":\"fNumber\"},null,{\"currentIsoSpeedRate\":\"250\",\"isoSpeedRateCandidates\":[\"AUTO\",\"50\",\"64\",\"80\",\"100\",\"125\",\"160\",\"200\",\"250\",\"320\",\"400\",\"500\",\"640\",\"800\",\"1000\",\"1250\",\"1600\",\"2000\",\"2500\",\"3200\",\"4000\",\"5000\",\"6400\",\"8000\",\"10000\",\"12800\",\"16000\",\"20000\",\"25600\",\"32000\",\"40000\",\"51200\",\"64000\",\"80000\",\"102400\",\"128000\",\"160000\",\"204800\"],\"type\":\"isoSpeedRate\"},null,null,{\"currentShutterSpeed\":\"1/100\",\"shutterSpeedCandidates\":[],\"type\":\"shutterSpeed\"},{\"checkAvailability\":true,\"currentColorTemperature\":-1,\"currentWhiteBalanceMode\":\"Auto WB\",\"type\":\"whiteBalance\"},null,{\"focusStatus\":\"Not Focusing\",\"type\":\"focusStatus\"},null,null,{\"candidate\":[\"Single\",\"Continuous\"],\"contShootingMode\":\"Single\",\"type\":\"contShootingMode\"},null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]}"
What is the best way to decode a json answer like that?
Use JSONSerialization and cast result to a dictionary of type [String: Any]
let data = string.data(using: .utf8)!
do {
let result = try JSONSerialization.jsonObject(with: data) as! [String: Any]
//extract info from result
if let array = result["result"] as? [Any] {
let item = array.filter( {
if let dict = $0 as? [String: Any] {
return dict.contains(where: { $0.key == "currentShootMode"})
}
return false
})
print(item)
}
} catch {
print(error)
}
to extract info from the item variable you need to cast again
if let mode = item.first as? [String: Any], let value = mode["currentShootMode"] {
print(value)
}

Get item out of array in Swift

I'm very new to Swift and have spent several hours just trying to pull the photo_url key out of a JSON response.
I'm using this for the reading the JSON:
let jsonDictionary = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
Then:
if let eventsDictionary = jsonDictionary {
let upcomingEvents = UpcomingEvents(eventsDictionary: eventsDictionary)
completion(upcomingEvents)
} else {
completion(nil)
}
Here is my (failed) attempt to pull out the key:
init(eventsDictionary: [String : Any]) {
//photoUrl = eventsDictionary[EventKeys.photoUrl] as? String
let groups: NSArray = eventsDictionary["groups"] as! NSArray
let url: String = groups[0]
print("THIS IS YOUR RETURNED PHOTO URL--\(url)--END OF RETURNED PHOTO URL")
}
I changed "[String: Any]" to [String: AnyObject] and now i get this...
There are problems casting Any to NSArray. Just make your Init method taking [String:AnyObject]. But, better use Array instead of NSArray here
Try to get url use following code.
let firstObj = groups[0] as! [String: String] // use if let to unwrap is better
let url = firstObj["photo_url"]
To get "photo_url" from the json file in your photo,
it looks like this:
init(eventsDictionary: [String : Any]) {
if let groups = eventsDictionary["groups"] as? [NSDictionary]{
/*
// Get All URL
var urls : [String] = []
for group in groups{
if let url = group.value(forKey: "photo_url"){
urls.append(url)
}
}
*/
// Groups[0] url
let url: String = groups[0].value(forKey: "photo_url") as! String
print("THIS IS YOUR RETURNED PHOTO URL--\(url)--END OF RETURNED PHOTO URL")
}
}
You need to read json as `[String: Any].
if let eventsDictionary = json as? [String: Any] {
let upcomingEvents = UpcomingEvents(eventsDictionary: eventsDictionary)
completion(upcomingEvents)
}
Then, init your UpcomingEvents model like this
init(eventsDictionary: [String : Any]) {
let groups: NSArray = eventsDictionary["groups"] as! NSArray
let group1 = groups[0] as! NSDictionary
let photoURL = group1["photo_url"] as! String
print(photoURL)
}

Parse JSON data in swift

I am trying to parse my json data in swift 3.0. I am using Alamofire 4.0+
Here is my json
{
"token":
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDQ0MjgzNzgxMTF9.CNonyvtQbRgaqqkdPO5KwqpVaUmlGrpaTqlBxmvaX80",
"expires": 1504428378111,
"user":
[{"user_id":13,"user_first_name":"Himanshu","user_last_name":"Srivastava","full_name":"Himanshu Srivastava"}]
}
Here is my model class to hold these values
import Foundation
import ObjectMapper
class LoginResult:Mappable{
var token:String?
var expires:Double?
var users:[[String:Any]]?
required init?(map:Map){
}
func mapping(map:Map)->Void{
self.token <- map["token"]
self.expires <- map["expires"]
self.users <- map["user"]
}
}
None of the solution available on internet worked for me. How can I parse this json and map to the model class?
Any help here?
I was mistaken, the value for key user is indeed a regular array.
This is a solution without a third party mapper and with an extra User struct (by the way the value for key expires is an Int rather than Double).
Assuming the user data comes from a database which always sends all fields the user keys are forced unwrapped. If this is not the case use optional binding also for the user data:
struct User {
let firstName : String
let lastName : String
let fullName : String
let userID : Int
}
class LoginResult {
let token : String
let expires : Int
var users = [User]()
init(json : [String:Any]) {
self.token = json["token"] as? String ?? ""
self.expires = json["expires"] as? Int ?? 0
if let users = json["user"] as? [[String:Any]] {
self.users = users.map { User(firstName: $0["user_first_name"] as! String,
lastName: $0["user_last_name"] as! String,
fullName: $0["full_name"] as! String,
userID: $0["user_id"] as! Int)
}
}
}
}
let json = "{\"token\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDQ0MjgzNzgxMTF9.CNonyvtQbRgaqqkdPO5KwqpVaUmlGrpaTqlBxmvaX80\",\"expires\":504428378111,\"user\":[{\"user_id\":13,\"user_first_name\":\"Himanshu\",\"user_last_name\":\"Srivastava\",\"full_name\":\"Himanshu Srivastava\"}]}"
let jsonData = json.data(using: .utf8)!
do {
if let userData = try JSONSerialization.jsonObject(with: jsonData) as? [String:Any] {
let loginResult = LoginResult(json: userData)
print(loginResult.users[0])
// do something with loginResult
}
} catch {
print(error)
}
Here is the answer with map replaced by dictionary. Don't forget to handle error or unwrap carefully :)
let str = "{\"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDQ0MjgzNzgxMTF9.CNonyvtQbRgaqqkdPO5KwqpVaUmlGrpaTqlBxmvaX80\",\"expires\": 1504428378111,\"user\": [{\"user_id\":13,\"user_first_name\":\"Himanshu\",\"user_last_name\":\"Srivastava\",\"full_name\":\"Himanshu Srivastava\"}]}"
let data = str.data(using: .utf8)
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String: Any]
//Pass this json into the following function
}catch let error{
}
func mapping(json:[String: Any]?)->Void{
self.token <- json?["token"] as? String
self.expires <- json?["expires"] as? Double
self.users <- json?["user"] as? [[String: Any]]
}

Strange behaviour of optionals in Swift 3

I have experienced a strange behaviour when parsing JSON data using Swift 3.
do {
let json = try JSONSerialization.jsonObject(with: data!, options: []) as! NSDictionary
let items:[AnyObject] = (json["items"] as? [AnyObject])!
for item in items {
let id:String = item["id"] as! String
print("ID: \(id)")
let info = item["volumeInfo"] as AnyObject
print(info)
let title = info["title"]
print(title)
}
} catch {
print("error thrown")
}
This produces the following output. Notice that info is an optional but if I try to unwrap it it states it is not an optional! The script crashes on let title = info["title"] As a result I can't access the title key. This behaviour has changed since Swift 2.
ID: lbvUD6LUyV8C
Optional({
publishedDate = 2002;
publisher = "Sams Publishing";
title = "Java Deployment with JNLP and WebStart";
})
You can do something like:
do {
let json = try JSONSerialization.jsonObject(with: data!) as! [String: Any]
let items = json["items"] as! [[String: Any]]
for item in items {
let id = item["id"] as! String
let info = item["volumeInfo"] as! [String: Any]
let title = info["title"] as! String
print(id)
print(info)
print(title)
}
} catch {
print("error thrown: \(error)")
}
I might suggest excising the code of the ! forced unwrapping (if the JSON was not in the form you expected, do you really want this to crash?), but hopefully this illustrates the basic idea.
The runtime type of info is Optional<Something>, but the compile time type (as you explicitly cast it) is AnyObject. How is the compiler supposed to know that the AnyObject will happen to be an Optional<Something> unless you tell it (in the form of a cast)?
Try:
let info = item["volumeInfo"] as AnyObject?
Now the compiler knows it's an Optional<AnyObject>, so you can unwrap it.
In Swift 3 the compiler must know the types of all subscripted objects if it's an array or dictionary. AnyObject – which has been changed to Any in Swift 3 – is not sufficient.
Since you know that the value for key volumeInfo is a dictionary cast it accordingly preferably using optional bindings
let info = item["volumeInfo"] as? [String:Any] {
print(info)
let title = info["title"] as! String
print(title)
}
This should do:
guard let json = try? JSONSerialization.jsonObject(with: data!, options: []) as! [String: AnyObject],
let items = json["items"] as! Array<AnyObject>? else {
return
}
for item in items {
let id = item["id"] as! String
if let info = item["volumeInfo"] as? [String: AnyObject] {
let title = info["title"] as! String
} else {
// do something
}
}