How to covert String to Array of Object in Swift - json

This is my first Question so I don't know a better way to ask it. My question is in Swift I am converting this String:
let points = "[{\"lat\":\"33.6240836\", \"lng\":\"73.0686886\"},{\"lat\":\"33.6235471\", \"lng\":\"73.0686249\"},{\"lat\":\"33.6234177\" , \"lng\":\"73.0681210\"},{\"lat\":\"33.6232655\" , \"lng\":\"73.0676921\"},{\"lat\":\"33.6241488\" , \"lng\":\"73.0683039\"}]"
By using the method:
let data = points.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)
}
But it returns:
[["lng": 73.0686886, "lat": 33.6240836], ["lng": 73.0686249, "lat": 33.6235471], ["lng": 73.0681210, "lat": 33.6234177], ["lng": 73.0676921, "lat": 33.6232655], ["lng": 73.0683039, "lat": 33.6241488]]
While what I need is:
[{"lng": "73.0686886", "lat": "33.6240836"}, {"lng": "73.0686249", "lat": "33.6235471"}, {"lng": "73.0681210", "lat": "33.6234177"}, {"lng": "73.0676921", "lat": "33.6232655"}, {"lng": "73.0683039", "lat": "33.6241488"}]
Can any body helps me how to achieve it in swift?

You asked about Array of Object so declare a struct and decode the JSON with Decodable
let points = "[{\"lat\":\"33.6240836\", \"lng\":\"73.0686886\"},{\"lat\":\"33.6235471\", \"lng\":\"73.0686249\"},{\"lat\":\"33.6234177\" , \"lng\":\"73.0681210\"},{\"lat\":\"33.6232655\" , \"lng\":\"73.0676921\"},{\"lat\":\"33.6241488\" , \"lng\":\"73.0683039\"}]"
struct Point : Decodable {
let lat, lng: String
}
let data = Data(points.utf8)
do {
let jsonArray = try JSONDecoder().decode([Point].self, from: data)
print(jsonArray)
} catch { // never cast to NSError
print(error)
}

Related

Decoder not decoding json at keypath

Im trying to decode some JSON, but it's not parsing it. I think it may have something to to with either an incorrect KeyPath or the object itself. But I cannot figure it out.
This is the JSON that I want to decode (I want the array inside the docs path):
{
"status": 200,
"data": {
"docs": [
{
"_id": "60418a6ce349d03b9ae0669e",
"title": "Note title",
"date": "2015-03-25T00:00:00.000Z",
"body": "this is the body of my note.....",
"userEmail": "myemail#gmail.com"
}
],
"total": 1,
"limit": 20,
"page": 1,
"pages": 1
},
"message": "Notes succesfully Recieved"
}
Here's my decode function:
extension JSONDecoder {
func decode<T: Decodable>(_ type: T.Type, from data: Data, keyPath: String) throws -> T {
let toplevel = try JSONSerialization.jsonObject(with: data)
if let nestedJson = (toplevel as AnyObject).value(forKeyPath: keyPath) {
let nestedJsonData = try JSONSerialization.data(withJSONObject: nestedJson)
return try decode(type, from: nestedJsonData)
} else {
throw DecodingError.dataCorrupted(.init(codingPath: [], debugDescription: "Nested json not found for key path \"\(keyPath)\""))
}
}
}
And i'm calling it like this:
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let notes = try decoder.decode([Note].self, from: data, keyPath: "data.docs")
Finally, this is my Note Struct:
struct Note: Codable {
var title: String?
let date: Date?
var body: String?
let userEmail: String?
}
The problem was that I was trying to decode date as a Date object instead of a String as is shown on the JSON.
Thanks #vadian!

Decode Custom Json with Decodable

I have this Json:
{ "first": {
"house": [
"small"
]
}, "second": {
"house": [
"small"
] }, "third": {
"car": [
"fast",
"economic"
] }, "fourth": {
"car": [
"fast",
"economic"
] }, "fifth": {
"car": [
"fast",
"economic"
],
"ice": [
"round",
"tasty"
],
"tree": [
"big",
"small"
] } }
I tried to set up a structure with Decodable but I do not get it to work:
struct secondLayer: Codable {
let exchange: [String: [String]]
}
struct decodeJson: Codable {
let symbol: [String: [secondLayer]]
static func decode(jsonString: String) - [decodeJson] {
var output = [decodeJson]()
let decode = JSONDecoder()
do {
let json = jsonString.data(using: .utf8)
output = try! decode.decode([decodeJson].self, from: json!)
} catch {
print(error.localizedDescription)
}
return output
}
}
I get this Error:
Fatal error: 'try!' expression unexpectedly raised an error:
Swift.DecodingError.typeMismatch(Swift.Array<Any>,
Swift.DecodingError.Context(codingPath: [], debugDescription:
"Expected to decode Array<Any but found a dictionary instead.",
underlyingError: nil)): file
/BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-900.0.74.1/src/swift/stdlib/public/core/ErrorType.swift,
line 181
I tried some modification but I do not get it to work.
The error message
"Expected to decode Array<Any> but found a dictionary instead."
is very clear. You want to decode an array ([decodeJson]) but the root object is a dictionary (starting with {)
Your code cannot work anyway. There are no keys exchange and symbol in the JSON.
Basically there are two ways to decode that JSON:
If all keys are dynamic you cannot decode the JSON to structs. You have to decode it to [String:[String:[String]]]. In this case Codable has no benefit over traditional JSONSerialization.
struct DecodeJson: Codable {
static func decode(jsonString: String) -> [String:[String:[String]]] {
var output = [String:[String:[String]]]()
let decoder = JSONDecoder()
do {
let json = Data(jsonString.utf8)
output = try decoder.decode([String:[String:[String]]].self, from: json)
print(output)
} catch {
print(error.localizedDescription)
}
return output
}
}
Or if the ordinal keys first, second etc are static use an umbrella struct
struct Root : Codable {
let first : [String:[String]]
let second : [String:[String]]
let third : [String:[String]]
let fourth : [String:[String]]
let fifth : [String:[String]]
}
struct DecodeJson {
static func decode(jsonString: String) -> Root? {
let decoder = JSONDecoder()
do {
let json = Data(jsonString.utf8)
let output = try decoder.decode(Root.self, from: json)
return output
} catch {
print(error.localizedDescription)
return nil
}
}
}
Of course you can decode house, car etc into a struct but this requires a custom initializer for each struct because you have to decode a single array manually with unkeyedContainer

wrong json format in swift

I'm trying to send json object to server. The server expects object to be in this format:
{
"Lat": 10.33688590000001,
"Name": "nameOfSomething",
"Lng": 58.43135800000005
}
but the object that I'm getting after defining object is this:
[
"Lat": 10.33688590000001,
"Name": nameOfSomething, //this is missing ""
"Lng": 58.43135800000005
]
the code that I'm using is this:
let jsonObject: [String: AnyObject] = [
"Lat": lat,
"Name": nameOfSender.text!,
"Lng": lng
]
let jsonData = try! NSJSONSerialization.dataWithJSONObject(jsonObject, options: .PrettyPrinted)
Any ideas how to solve this?
Please Look on this. it will give you correct answer.
/// Use this method to get JSON string from Dictionary.
///
///
/// - returns: `String` for Dictionary
func getJSONStringForDictionary(dict:[String:AnyObject]) -> String {
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(dict, options: [])
if let jsonString = NSString(data: jsonData, encoding: NSUTF8StringEncoding) as? String {
return jsonString
}
// here "jsonData" is the dictionary encoded in JSON data
} catch let error as NSError {
print(error)
}
return ""
}
/* calling */
let json = self.getJSONStringForDictionary(jsonObject)
print(json)
//{
"Lat" : 10.33688590000001,
"Name" : "nameOfSomething",
"Lng" : 58.43135800000005
}

Parse twitter trend api results in swift

I using twitter trend api to get the name of all the trends.
I have the following setup:
let url = "\(APIConstants.Twitter.APIBaseURL)1.1/trends/place.json?id=1"
let client = TWTRAPIClient()
let statusesShowEndpoint = url
let params = ["id": "20"]
var clientError : NSError?
let request = client.urlRequest(withMethod: "GET", url: statusesShowEndpoint, parameters: params, error: &clientError)
client.sendTwitterRequest(request) { (response, data, connectionError) -> Void in
if connectionError != nil {
print("Error: \(connectionError)")
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: [])
} catch let jsonError as NSError {
print("json error: \(jsonError.localizedDescription)")
}
}
and after the call, json has the following data:
(
{
"as_of": "2012-08-24T23:25:43Z",
"created_at": "2012-08-24T23:24:14Z",
"locations": [
{
"name": "Worldwide",
"woeid": 1
}
],
"trends": [
{
"tweet_volume": 3200,
"events": null,
"name": "#GanaPuntosSi",
"promoted_content": null,
"query": "%23GanaPuntosSi",
"url": "http://twitter.com/search/?q=%23GanaPuntosSi"
},
{
"tweet_volume": 4200,
"events": null,
"name": "#WordsThatDescribeMe",
"promoted_content": null,
"query": "%23WordsThatDescribeMe",
"url": "http://twitter.com/search/?q=%23WordsThatDescribeMe"
},
{
"tweet_volume": 2200,
"events": null,
"name": "Sweet Dreams",
"promoted_content": null,
"query": "%22Sweet%20Dreams%22",
"url": "http://twitter.com/search/?q=%22Sweet%20Dreams%22"
}
]
}
)
From the above json data, i want to store all the name inside trends in an array in swift.
There is some data checking and casting you need to do to make sure you're getting back the data in the structure you'd expect, and then from there its simple iteration. Something along these lines should get you going:
let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:Any]
var names = [String]()
if let trends = json?["trends"] as? [[String:Any]] {
for trend in trends {
if let name = trend["name"] as? String {
names.append(name)
}
}
}
Note the various as? type checks to iterate over the structure safely. For a more in-depth review of cleanly working with JSON in Swift including reading the data in to type-safe structs, check out this official blog post from Apple.

Unwrapping Json Swift (found nil)

i currently trying to decode Json in Xcode, but i not succed to get one of them.
This is what i get :
[
{
"id": "1",
"title": "bmw",
"price": "500.00",
"description": "330",
"addedDate": "2015-05-18 00:00:00",
"user_id": "1",
"user_name": "CANOVAS",
"user_zipCode": "32767",
"category_id": "1",
"category_label": "VEHICULES",
"subcategory_id": "2",
"subcategory_label": "Motos",
"bdd": {}
}
"pictures":
[
{ "name": "http://cars.axlegeeks.com/sites/default/files/4315/media/images/2014_BMW_Z4_sDrive28i_3790993.jpg"
}
]
}
]
And i want to get the value of "name" for the "Pictures" lines but i have the error "unexpectedly found nil while unwrapping value".
For the others values i proceed this way :
let jsonData:NSDictionary = NSJSONSerialization.JSONObjectWithData(urlData!, options:NSJSONReadingOptions.MutableContainers , error: &error) as! NSDictionary
//Browse into JSON to get datas
let resp = jsonData["0"] as! NSDictionary
let user_nameR = resp["user_name"] as! String
let user_zipCodeR = resp["user_zipCode"] as! String
let titleR = resp["title"] as! String
let priceR = resp["price"] as! String
let descriptionR = resp["description"] as! String
Thank's for your help !
Pictures is in not in the subdictionary your other values are. This should work, but you should check all values if they are nil before you force cast them.
if let pictureArray = jsonData["pictures"] as? NSArray
{
if let pictureDict = pictureArray.firstObject as? NSDictionary
{
if let pictureName = pictureDict.objectForKey("name") as? String
{
NSLog("Picture name: %#", pictureName)
}
}
}
jsonData contains two sub-dictionaries, one without a key and one with key 'pictures'. Pictures is an array containing one sub-dictionary.