I am trying to use a string I am getting from a database as JSON using swift. I have tried to convert the string to a data object and then use JSONSerialization, but the results always come back nil.
Here is a sample of my code:
var string = "{Param1: \"Value\", Param2: \"value2\", Param3: \"value3\"}"
let data = (reducedOptionsString as NSString).dataUsingEncoding(NSUTF8StringEncoding)
if let d = data{
var err : NSErrorPointer = nil
let parsedObject: AnyObject? = NSJSONSerialization.JSONObjectWithData(d, options: NSJSONReadingOptions.MutableLeaves, error: err)
if let dict = parsedObject as? Dictionary<String, AnyObject>{
...
}
}
For some reason parsedObject always comes back as nil
Does anyone know what I might be missing to convert my string data to a JSON object that I can use?
Your json is not valid, keys must me enclosed in quotes too.
"{ \"Param1\": \"Value\", \"Param2\": \"value2\", \"Param3\": \"value3\"}"
Also, as #zaph pointed out, it's variable string the one you want to convert to data.
var string = "{\"Param1\": \"Value\", \"Param2\": \"value2\", \"Param3\": \"value3\"}"
if let data = string.dataUsingEncoding(NSUTF8StringEncoding){
var err : NSErrorPointer = nil
let parsedObject = NSJSONSerialization.JSONObjectWithData(
data!,
options: NSJSONReadingOptions.MutableLeaves,
error: err) as? Dictionary<String, AnyObject>
if (parsedObject != nil) {
...
}
else {
if (err != nil) {
println("Error: \(err)")
}
else {
println("Error: unexpected error parsing json string")
}
}
}
Alternatively, you could use SwiftyJSON, a very popular library to handle json on swift that could make your life a little easier.
var string = "{\"Param1\": \"Value\", \"Param2\": \"value2\", \"Param3\": \"value3\"}"
if let data = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding)
{
var err : NSErrorPointer = nil
let parsedObject: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableLeaves, error: err)
if (err != nil)
{
println("error handling...")
}
if let dict = parsedObject as? Dictionary<String, AnyObject>
{
println("XD")
}
}
You just replace following 2 lines in your OWN code, rest will be work fine.
:)
var string = "{\"Param1\": \"Value\", \"Param2\": \"value2\", \"Param3\": \"value3\"}"
let data = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding)
Swift 5 Example:
let properties: [(String, Any?)] = [("firstName", firstName),
("lastName", lastName),
("city", city),
("state", state),
("zipCode", zipCode),
("country", country)]
let body = properties.compactMap({ property -> (String, Any)? in
if let value = property.1 {
return (property.0, value)
} else {
return nil
}
})
let jsonDict = Dictionary(uniqueKeysWithValues: body)
let jsonData = try? JSONSerialization.data(withJSONObject: jsonDict, options: [])
Related
I try to convert JSON string to a JSON object but after JSONSerialization the output is nil in JSON.
Response String:
[{\"form_id\":3465,\"canonical_name\":\"df_SAWERQ\",\"form_name\":\"Activity 4 with Images\",\"form_desc\":null}]
I try to convert this string with my code below:
let jsonString = response.result.value
let data: Data? = jsonString?.data(using: .utf8)
let json = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String:AnyObject]
print(json ?? "Empty Data")
The problem is that you thought your jsonString is a dictionary. It's not.
It's an array of dictionaries.
In raw json strings, arrays begin with [ and dictionaries begin with {.
I used your json string with below code :
let string = "[{\"form_id\":3465,\"canonical_name\":\"df_SAWERQ\",\"form_name\":\"Activity 4 with Images\",\"form_desc\":null}]"
let data = string.data(using: .utf8)!
do {
if let jsonArray = try JSONSerialization.jsonObject(with: data, options : .allowFragments) as? [Dictionary<String,Any>]
{
print(jsonArray) // use the json here
} else {
print("bad json")
}
} catch let error as NSError {
print(error)
}
and I am getting the output :
[["form_desc": <null>, "form_name": Activity 4 with Images, "canonical_name": df_SAWERQ, "form_id": 3465]]
Using JSONSerialization always felt unSwifty and unwieldy, but it is even more so with the arrival of Codable in Swift 4. If you wield a [String:Any] in front of a simple struct it will ... hurt. Check out this in a Playground:
import Cocoa
let data = "[{\"form_id\":3465,\"canonical_name\":\"df_SAWERQ\",\"form_name\":\"Activity 4 with Images\",\"form_desc\":null}]".data(using: .utf8)!
struct Form: Codable {
let id: Int
let name: String
let description: String?
private enum CodingKeys: String, CodingKey {
case id = "form_id"
case name = "form_name"
case description = "form_desc"
}
}
do {
let f = try JSONDecoder().decode([Form].self, from: data)
print(f)
print(f[0])
} catch {
print(error)
}
With minimal effort handling this will feel a whole lot more comfortable. And you are given a lot more information if your JSON does not parse properly.
I tried the solutions here, and as? [String:AnyObject] worked for me:
do{
if let json = stringToParse.data(using: String.Encoding.utf8){
if let jsonData = try JSONSerialization.jsonObject(with: json, options: .allowFragments) as? [String:AnyObject]{
let id = jsonData["id"] as! String
...
}
}
}catch {
print(error.localizedDescription)
}
I used below code and it's working fine for me. :
let jsonText = "{\"userName\":\"Bhavsang\"}"
var dictonary:NSDictionary?
if let data = jsonText.dataUsingEncoding(NSUTF8StringEncoding) {
do {
dictonary = try NSJSONSerialization.JSONObjectWithData(data, options: [.allowFragments]) as? [String:AnyObject]
if let myDictionary = dictonary
{
print(" User name is: \(myDictionary["userName"]!)")
}
} catch let error as NSError {
print(error)
}
}
static func getJSONStringFromObject(object: Any?) -> String? {
do {
let jsonData = try JSONSerialization.data(withJSONObject: object ?? DUMMY_STRING, options: [])
return String(data: jsonData, encoding: .utf8) ?? DUMMY_STRING
} catch {
print(error.localizedDescription)
}
return DUMMY_STRING
}
I am trying to get data out of an array of nested dictionaries which is the result of a JSON response.
func fetchData() {
let urlString = "https://global.api.pvp.net/api/lol/static-data/na/v1.2/champion?api_key=\(self.apiKey)"
let url = URL(string: urlString)
URLSession.shared.dataTask(with:url!) { (data, response, error) in
if error != nil {
print(error ?? "ERROR!")
} else {
do {
let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String:Any]
print(parsedData)
print(parsedData["type"] ?? "")
print(parsedData["version"] ?? "")
print(type(of: parsedData))
print(type(of: parsedData["data"]!))
//ERROR HERE.
//"Cannot subscript a value of type '[String, Any]' with an index of type '(String, (String, Any).Type)'
let innerItem = parsedData["Aatrox", (String, Any)]
} catch let error as NSError {
print(error)
}
}
}.resume()
Here is what is printed:
["type": champion, "version": 7.4.3, "data": {
Aatrox = {
id = 266;
key = Aatrox;
name = Aatrox;
title = "the Darkin Blade";
};
Ahri = {
id = 103;
key = Ahri;
name = Ahri;
title = "the Nine-Tailed Fox";
};
Akali = {
id = 84;
key = Akali;
name = Akali;
title = "the Fist of Shadow";
};
Alistar = {
id = 12;
key = Alistar;
name = Alistar;
title = "the Minotaur";
};
}]
champion
7.4.3
Dictionary<String, Any>
__NSDictionaryI
I am trying to get the "id" for "Aatrox".
How would i go about doing this?
is it because the type of parsedData["data"]! is __NSDictionaryI??
Thanks for the help.
First you need to extract data Dictionary then access other dictionary.
do {
let parsedData = try JSONSerialization.jsonObject(with: data!, options: []) as! [String:Any]
if let passDic = parsedData["data"] as? [String:Any],
let innerItem = passDic["Aatrox"] as? [String: Any] {
print(innerItem)
}
} catch {
print(error)
}
Seems like it should be let innerItem: [String: Any] = parsedData["Aatrox"]
let data : [string:Any] = parsedData.value(key: "data")
let aatrox : [string:Any] = data["Aatrox"]
print("**id**\(aatrox["id"])")
this thing work for me..
So i recently updated to Swift 3/XCode 8 and some of my code went hay-wire. I've read that some syntax changes have been made but I can't seem get this one right.
I make a request to Twitter and get JSON back:
func forLoadStats(completion: (AnyObject?, NSError?) -> Void)
{
var clientError: NSError?
let idString = api.getUserID()
let client = TWTRAPIClient()
let request = client.urlRequest(withMethod: "GET", url: "https://api.twitter.com/1.1/users/show.json", parameters: ["user_id" : 27446437], error: &clientError)
client.sendTwitterRequest(request)
{ (response, data, connectionError) in
if (connectionError == nil)
{
do {
if let json: Any = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [AnyObject]
{
if let json = json, let immage = json?["profile_image_url_https"] as? String
{
//Make ProfilePic edges round
self.profPic.layer.cornerRadius = 42
self.profPic.clipsToBounds = true
//let immage = image["profile_image_url_https"] as String
let _vImageUrl = immage.replacingOccurrences(of: "_normal", with: "")
let urlProfilePic = NSURL(string: _vImageUrl)
let urlPP = NSData(contentsOf: urlProfilePic! as URL)
self.profPic.image = UIImage(data: urlPP! as Data)
let ScrName = json["screen_name"] as! String
self.scrNameLabel.text = "#\(ScrName)"
//Populate Followers Label.text
let flwrVar = json["followers_count"] as! Int
self.followerLbl.text = "\(flwrVar)"
//Populate Following Label.text
let flwngVar = json["friends_count"] as! Int
self.followingLbl.text = "\(flwngVar)"
//Populate Bio
let bio = json["description"] as! String
self.bioLabel.text = "\(bio)"
//created at date
let accountAge = json["created_at"] as! String
self.createdLbl.text = "\(accountAge)"
let tweetCount = json["statuses_count"] as! Int
self.tweetCount.text = "\(tweetCount)"
let likes = json["favourites_count"] as! Int
self.likesCount.text = "\(likes)"
let lists = json["listed_count"] as! Int
self.listedCount.text = "\(lists)"
}
}
}
catch let error
{
print(error)
}
}
}
}
I get an error on the second "If let" statement that says: "initializer for conditional binding must have optional type not 'Any.
Can someone explain why this is?
Your JSON is obviously a dictionary, a JSON dictionary in Swift 3 is [String:Any]
You caused the error by the silly Any annotation (which is supposed to be Any? but is practically nonsensical) because it confuses the compiler.
If you use a do block, try without question mark but use optional binding:
...
if let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:Any] {
if let immage = json["profile_image_url_https"] as? String { ...
There are a couple of problems with the syntax. [AnyObject] will not work to use reference items such as json["profile_image_url_https"]. also, you are redeclaring json through let json = json, which makes it a non option in your let immage = json?["profile_image_url_https"] call, so that becomes a problem. This structure does not have any compiler errors
if let json = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:Any]
{
if let json = json, let immage = json["profile_image_url_https"] as? String
{
}
}
This does not have any compiler errors.
do{
let resultJSON = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions())
let arrayJSON = resultJSON as! NSArray
let success:NSInteger = arrayJSON["success"] as! NSInteger
if (success == 1 ) ....
json data is the response from the server, i am trying to convert it to integer but i get the conversation error.
This is a working exmaple (tested on my machine)
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let data = data{
print("data =\(data)")
do{
let resultJSON = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions())
let resultDictionary = resultJSON as? NSDictionary
let success = resultDictionary!["success"]!
let successInteger = success as! Int
print("success = \(success)")
if successInteger == 1 {
print("yes")
}else{
print("no")
}
}catch _{
print("Received not-well-formatted JSON")
}
}
if let response = response {
print("url = \(response.URL!)")
print("response = \(response)")
let httpResponse = response as! NSHTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
where the response is:
{ "error_message" : "No User", "success" : 0}
Note
you said that your server responnes as:
{ "error_message" = "No User"; success = 0; }
and this is not a valid json, you should correct it to match the json that i gave to you
You're casting resultJSON as an NSArray but then you try to use it as a dictionary by subscripting "success".
If the response is a dictionary, then cast the result as a dictionary:
let result = resultJSON as! NSDictionary
let success = result["success"] as! NSInteger
If the response is an array of dictionaries, then first select one of the items before subscripting.
let arrayJSON = resultJSON as! NSArray
let success = arrayJSON[0]["success"] as! NSInteger
Note: when possible, prefer using Swift's typed arrays an dictionaries rather than Foundation's NSArray and NSDictionary. Also you should avoid force casting with !, it's better to unwrap optionals safely with if let ... = ... as? ... or any other mechanism.
Update
Here's an example:
do {
let resultJSON = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions())
var success = 0
if let dictJSON = resultJSON as? [String:AnyObject] {
if let successInteger = dictJSON["success"] as? Int {
success = successInteger
} else {
print("no 'success' key in the dictionary, or 'success' was not compatible with Int")
}
} else {
print("unknown JSON problem")
}
if success == 1 {
// yay!
} else {
// nope
}
In this example I'm using a Swift dictionary [String:AnyObject] instead of an NSDictionary, and I'm using a Swift integer Int instead of Foundation's NSInteger. I'm also typecasting with if let instead of forcing.
I tried to get the value of "seed" from json response. But i am getting nil.
Json Response:
{
"response": {
"params": {
"rows": "20",
"defType": "abc",
"seed": "381786611"
}
}
}
Swift Parsing:
if let responseHeader:AnyObject = object?["response"] as? NSDictionary {
if let t = (responseHeader["params"] as? NSDictionary){
let t1 = t["seed"] as? String
println("result is \(t1)") // This returns nil
}
}
Json Parsing
func processJsonToDictionary(object:AnyObject?) -> AnyObject?{
if object != nil {
if let data: AnyObject = object {
var parseError: NSError?
var jsonResult = NSJSONSerialization.JSONObjectWithData(object as NSData!, options: NSJSONReadingOptions.MutableContainers, error: &parseError) as? NSDictionary
if(parseError != nil){
return parseError
}
else{
return jsonResult
}
}
}
return nil
}
I am not able to get the value of t1. it always returns nil.
How can i get the value.
Also, I put a breakpoint and tried to print the value of t1. But the Xcode Keeps crashing. Why?
I think the major problem here is only accessing a JSON object in swift.
var error: NSError?
let jsonDict = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &error) as NSDictionary
let resp = jsonDict["response"] as? NSDictionary
let params = resp?["params"]?["seed"]
let seed = params!! as NSString
This is just to show you how a JSON object is accessed in swift. You can ofcourse change it according to your needs to remove unwanted Optional Chaining.
For easy JSON manipulation in Swift you could try this little library. It seems pretty easy and you could do this:
var dictionary: [String: AnyObject]!
if let json = NKJSON.parse(yourNSDataObject) {
dictionary <> json[NKJSON.rootKey]
}
First confirm that the response which you are getting is in json format or in string format.
For json parsing you can use swifty json pod