Getting nil value when read JSON data in Swift - swift

if let postString = NSString(data:data!, encoding: NSUTF8StringEncoding) as? String {
guard let jsonData = postString.dataUsingEncoding(NSASCIIStringEncoding) else {
fatalError()
}
guard let jsonObjects = try? NSJSONSerialization.JSONObjectWithData(jsonData,options: [])
,let JSONArray = jsonObjects as? [[String: AnyObject]]
else {
fatalError()
}
print(JSONArray)
}
In postString constant, I am getting "[{\"Name\":\"ABC\",\"Age\":35},{\"Name\":\"CDE\",\"Age\":36‌​}]"
and when I run this code then fatalError() code call.

A couple of other people have explained what you did wrong in this case (Tried to cast the output of deserialization to a dictionary when it actually contains an array.)
Stepping back from the details, when something fails, you need to break your code into smaller pieces and then trace through it to see what's failing.
The "as?" cast says "Try to cast this object to another type. Wrap the results in an Optional." If the cast fails, the result is nil. If it succeeds, the optional contains the new type.
If you rewrote your code as:
let jsonObject = try NSJSONSerialization.JSONObjectWithData(data!,
options: NSJSONReadingOptions.AllowFragments)
guard let jsonDict = jsonObject as [String: Any] else {
print("Cast failed")
return
}
Then the print statement would fire and you'd know that the cast was the problem.
EDIT:
I just noticed that your JSON data contains an array of dictionaries of type [String: Int]. In Swift Ints are not an Object type, so you need to cast your results to [[String:Any]], not [[String:AnyObject]]. I've fixed my code above.
I Wrote the following code in a playground and it works:
let jsonString = "[{\"Name\":\"ABC\",\"Age\":35},{\"surveyName\":\"CDE\",\"Age\":36}]"
guard let jsonData = jsonString.data(using: .ascii) else {
fatalError()
}
guard let jsonObjects = try? JSONSerialization.jsonObject(with: jsonData, options: []),
let JSONArray = jsonObjects as? [[String: Any]]
else {
fatalError()
}
print(String(describing: jsonObjects))
It gives the output:
(
{
Age = 35;
Name = ABC;
},
{
Age = 36;
surveyName = CDE;
}
)
Which is what I would expect.
EDIT #2:
Actually, on further investigation I'm stumped as to why your code isn't working. I just tested it, and the as [[String: AnyObject]] works. It turns out that in Swift 3 if you cast an Int to AnyObject and you've included Foundation (or UIKit) then it gets silently converted to an NSNumber, which IS an Object type.
You're going to need to show your actual JSON data and the code that converts it to an object if you need help debugging it.
EDIT #3:
Below is code I wrote and tested in Swift 2.3:
func parseJSONTest() {
let jsonString = "[{\"Name\":\"ABC\",\"Age\":35},{\"surveyName\":\"CDE\",\"Age\":36}]"
guard let jsonData = jsonString.dataUsingEncoding(NSASCIIStringEncoding) else {
fatalError()
}
//I'm not sure why you take JSON data, convert it to a string, and convert
//It back to NSData, but to prove a point, this is your code being fed
//well-formed JSON data in an NSData object:
if let postString = NSString(data:jsonData,
encoding: NSASCIIStringEncoding) as? String {
guard let jsonData = postString.dataUsingEncoding(NSASCIIStringEncoding) else {
fatalError()
}
guard let jsonObjects = try? NSJSONSerialization.JSONObjectWithData(jsonData,options: []),
let JSONArray = jsonObjects as? [[String: AnyObject]]
else {
fatalError()
}
print(JSONArray)
}
}
In order to provide a complete test I first take a string containing JSON data and convert it to NSData. I then convert that NSData back to JSON objects and cast them to the desired type, and it works. The code above displays:
[["Name": ABC, "Age": 35], ["surveyName": CDE, "Age": 36]]
Which matches the structure you have (an array of dictionaries).

The above is technically not an json object it is a json array.
Try casting as [AnyObject] instead of [String: AnyObject]
Then use the array to access the item you need. Then cast that to
[String:AnyObject]
because they are json objects within a json array

Related

Json array Dictionary parse nil in swift 5

I have a json like bellow ..
{"type": "Polygon","coordinates":[[[90.40082675305842,23.708825220302813],[90.4018551231959,23.708188760430843],[90.40247361862504,23.7091957460091],[90.40143983815886,23.70975584674032],[90.40082675305842,23.708825220302813]]]}
I have used bellow code to parse which returns nil
let json = myjsonString as? [String: Any]
But it returns nil. please help me to parse above json
You have to deserialize the string, either with JSONSerialization or – more comfortable – with JSONDecoder
let jsonString = """
{"type": "Polygon","coordinates":[[[90.40082675305842,23.708825220302813],[90.4018551231959,23.708188760430843],[90.40247361862504,23.7091957460091],[90.40143983815886,23.70975584674032],[90.40082675305842,23.708825220302813]]]}
"""
struct Overlay : Decodable {
let type : String
let coordinates : [[[Double]]]
}
do {
let result = try JSONDecoder().decode(Overlay.self, from: Data(jsonString.utf8))
print(result)
} catch {
print(error)
}
At first, you need to convert data from your input string then you can convert data to dictionary object. You can try this example.
let jsonText = "{\"first_name\":\"Sergey\"}"
var dictonary:NSDictionary?
if let data = jsonText.data(using: String.Encoding.utf8) {
do {
dictonary = try JSONSerialization.jsonObject(with: data, options: []) as? [String:AnyObject]
if let myDictionary = dictonary {
print(" First name is: \(myDictionary["first_name"]!)")
}
} catch let error as NSError {
print(error)
}
}

How to check JSON can be converted to dictionary in Swift?

Tried this, but get error:
var d = (try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers)) as [String: String]
guard let d2 = d else {
return
}
You can try
guard let dic = try? JSONSerialization.jsonObject(with: data) as? [String: String] else { return }
The right tool here is JSONDecoder, not JSONSerialization:
let d = try JSONDecoder().decode([String: String].self, data)
.mutableContainers doesn't make sense when converting to a Swift Dictionary. That causes it to create NSMutableDictionary objects, which will just be converted to [String: String] exactly the same as without .mutableContainers (but possibly with an extra copy step).

How to assign elements of a dictionary to JSON object in Vapor 3?

In Vapor 1.5 I used to assign the elements of an existing dictionary to a JSON object as shown below. How can I do this Vapor 3?
func makeCustomJSON(jsonFromReading: JSON, clientData: DataFromClient) throws -> JSON{
var dictionaryOfStrings = [String:String]()
dictionaryOfStrings["ChangesMadeBy"] = "Cleaner"
dictionaryOfStrings["BookingNumber"] = clientData.bookingNumber
dictionaryOfStrings["Claimed"] = "false"
//some 50 properties more...
//object read from /Users
var finalJsonObj = jsonFromReading
//assign the values of dictionaryOfStrings to finalJsonObj
for i in dictionaryOfStrings {
let key = i.key
let value = i.value
finalJsonObj[key] = try JSON(node:value)
}
//make json from object under CancelledBy and assign it to arrayOfTimeStampObjs
var arrayOfTimeStampObjs = try jsonFromReading["CancelledBy"]?.makeJSON() ?? JSON(node:[String:Node]())
//assign dictionaryOfStrings to current time stamp when booking is claimed
arrayOfTimeStampObjs[clientData.timeStampBookingCancelledByCleaner] = try JSON(node:dictionaryOfStrings)
finalJsonObj["CancelledBy"] = arrayOfTimeStampObjs
return finalJsonObj
} //end of makeCustomJSON
This is basically, JSON serialization in swift. Decoding the JSON object to a Dictionary and then modifying the dictionary and creating a new JSON.
router.get("test") { req -> String in
let jsonDic = ["name":"Alan"]
let data = try JSONSerialization.data(withJSONObject: jsonDic, options: .prettyPrinted)
let jsonString = String(data: data, encoding: .utf8)
return jsonString ?? "FAILED"
}
router.get("test2") { req -> String in
do {
// Loading existing JSON
guard let url = URL(string: "http://localhost:8080/test") else {
return "Invalid URL"
}
let jsonData = try Data(contentsOf: url)
guard var jsonDic = try JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) as? [String:String] else {
return "JSONSerialization Failed"
}
// Apply Changes
jsonDic["name"] = "John"
// Creating new JSON object
let data = try JSONSerialization.data(withJSONObject: jsonDic, options: .prettyPrinted)
let jsonString = String(data: data, encoding: .utf8)
return jsonString ?? "FAILED"
}catch{
return "ERROR"
}
}
I strongly recommend to create struct or class for your data type. It would be much safer in casting using the codable protocol and much easier to convert between JSON and your objects type because of the content protocol in vapor version 3.

Downcast from 'String?!' to 'String' only unwraps optionals; did you mean to use '!!'? in swift

source-code are bellow
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
if let blogs = json["profile_image_url"] as? String {
userImage = blogs//json["profile_image_url"] as! String
print("USER IMAGE:\(userImage)")
how i solve this issue
You want to test and unwrap any Optional before you use them. This includes casts like as?. If you can avoid it you should not use forced-unwrapping or explicitly-unwrapped Optional (marked with a !) because they lead to unexpected runtime crashes.
import Foundation
// create test data
let testJson = ["profile_image_url": "http://some.site.com/"]
var data: NSData?
// convert to NSData as JSON
do {
data = try NSJSONSerialization.dataWithJSONObject(testJson, options: [])
} catch let error as NSError {
print(error)
}
// decode NSData
do {
// test and unwrap data
if let data = data {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
// test and unwrap cast to String
if let userImage = json["profile_image_url"] as? String {
print("USER IMAGE:\(userImage)")
}
}
} catch let error as NSError {
print(error)
}

swift uploadTaskWithRequest with didReceiveData

I am pretty new to swift i have the following code
var data : AnyObject
let dict = jsonObject as NSDictionary
do
{
data = try NSJSONSerialization.dataWithJSONObject(dict, options:.PrettyPrinted)
let strData = NSString(data: data as! NSData, encoding: NSUTF8StringEncoding)! as String
data = strData.dataUsingEncoding(NSUTF8StringEncoding)!
let task = defaultSession.uploadTaskWithRequest(request, fromData: data as? NSData,
completionHandler:
{(data,response,error) in
guard let _:NSData = data, let _:NSURLResponse = response where error == nil
else {
return
}
});
task.resume()
}catch{
return resultJson
}
the resultJson object returns a empty array as there are more date to be downloaded and it takes time.I am wondering weather i can use didReceiveData option to return data after it is downloaded. I searched for code online but couldn't find any. Any help with code is much appreciated.
Thanks
You're right in that the return will run before the upload is finished, and therefore you won't get the desired result. I assume this code is in a function. You need to change it to take a closure as a parameter. Then when the upload is finished, you call that closure. Something like:
func doTheUpload(completion completionHandler: ((AnyObject?) -> Void)) {
var data : AnyObject
let dict = jsonObject as NSDictionary
do
{
data = try NSJSONSerialization.dataWithJSONObject(dict, options:.PrettyPrinted)
let strData = NSString(data: data as! NSData, encoding: NSUTF8StringEncoding)! as String
data = strData.dataUsingEncoding(NSUTF8StringEncoding)!
let task = defaultSession.uploadTaskWithRequest(request, fromData: data as? NSData,
completionHandler:
{(data,response,error) in
guard let _:NSData = data, let _:NSURLResponse = response where error == nil
completionhandler(resultJson)
else {
return
}
});
task.resume()
}catch{
// Do something for error
}
}
Then you would call it as:
doTheUpload(completion: {
resultJson in
// use the result
})
Note that I don't know where you're getting resultJson from or what type it is, so you will have to make some changes.