Json array Dictionary parse nil in swift 5 - swift

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)
}
}

Related

Appending JSON data Swift

I am currently working on a school project where I need to be able to read, write and view information from a JSON file. For my assignment, I am attempting to build an app that is a dictionary where you can add your own words, definitions, etc.
I have been stuck on trying to write the new data to the JSON file without overwriting the old.
I also have an error on the last line that I am confused about.
Here is the code that I have so far.
func fileUrl() -> URL {
let documentURL = try!
FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
return documentURL.appendingPathComponent("data.json")
}
#IBAction func addWords(_ sender: UIButton) {
if let oldWords:[[String : String]] = getJsonData() as [[String:String]]? {
if let oldJson = try? JSONSerialization.data(withJSONObject: oldWords, options: []) {
// Add old words to JSON file
}
}
let data: [String:String] = [
"Name": nameField.text ?? "N/A",
"Part of Speech": posField.text ?? "N/A",
"Definition": defView.text ?? "N/A"
]
let url = fileUrl()
if let jsonData = try? JSONSerialization.data(withJSONObject: data, options: []) {
// Append data into JSON file
print(data)
nameField.text = ""
defView.text = ""
posField.text = ""
} else {
print("Failed to save")
}
}
func getJsonData() -> [[String:String]]? {
let url = fileUrl()
let responseData: Data? = try! Data(contentsOf: url)
if let responseData = responseData {
let json: String? = try? JSONSerialization.jsonObject(with: responseData, options: []) as? String
if let dictionary: [[String:String]]? = json as? [[String:String]]? {
return dictionary
}
}
} // Missing return in a function expected to return '[[String : String]]?' error
#IBAction func loadData(_ sender: UIButton) {
let url = fileUrl()
let responseData: Data? = try! Data(contentsOf: url)
if let responseData = responseData {
let json: Any? = try? JSONSerialization.jsonObject(with: responseData, options: [])
if let json = json {
let dictionary: [String: Any]? = json as? [String: Any]
if let dictionary = dictionary {
for names in dictionary {
let name: String = dictionary["Name"] as! String
let definition: String = dictionary["Definition"] as! String
let pos: String = dictionary["Part of Speech"] as! String
print(name, definition, pos)
textView.text = ("Name: \(name) (\(pos))\n Definition: \(definition)\n ")
}
}
}
}
}
I have been researching a way to add the JSON data but maybe I have been staring at the code so long that I am missing an easy fix.
There is no native way in swift, nor with a third party library to append json objects to a file.
What you need to do is, when you call getJsonData -- you save the whole contents of that JSON into a variable and append from there. I recommend looking at Daniel's answer for an easy extension for appending JSON together. Let me know if you need any more help!
Regarding your error on the last line - It is good practice to never force un-wrap variables. It's hard to tell given we can't see the JSON tree; but make sure you are accessing the correct spot. print(dictionary) your dictionary and try some debugging and/or create validation for your array.

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.

Getting nil value when read JSON data in 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

Convert JSON String to Swift Dictionary

I'm trying to convert a json string to a dictionary.
I came across this answer but it only works for arrays with one value.
Here is an example of a string I'm trying to turn into a swift dictionary
[
{"value1":"Reporting for duty"},
{"value2":"Post received"},
{"value3":"frogg222"},
{"value4":"Still reporting"}
]
Just to be clear, the following code does not work and will return nil with the above string.
func convertStringToDictionary(text: String) -> [String:AnyObject]? {
if let data = text.data(using: String.Encoding.utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String:AnyObject]
} catch let error as NSError {
print(error)
}
}
return nil
}

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)
}