Convert an array of objects to JsonArray in Swift3 - json

I have my DataModel as this and it has a function name toJSON which converts this object to string representation of JSON
ContactEntry: NSObject {
var name: String!
var phone: String?
var email: String?
func toJson() -> String {
var dict : [String: AnyObject] = [:]
dict["name"] = (self.name ?? "") as AnyObject
dict["phone"] = (self.phone ?? "") as AnyObject
dict["email"] = (self.email ?? "") as AnyObject
guard let data = try? JSONSerialization.data(withJSONObject: dict, options: []) else{
return "{}"
}
guard let jsonString = String(data: data, encoding: String.Encoding.utf8) else {
return "{}"
}
return jsonString
}
}
It works very fine until now as I am getting correct JSON representation for this object.
Now I have to convert an array of ContactEntry to JsonArray.
I am doing this way but I am getting very weird symbols in the result string.
Let's say
var contacts = [ContactEntry]()
var contactsStr = [String]()
...
for contact in contacts{
contactsStr.append(contact.toJson())
}
do{
let data = try? JSONSerialization.data(withJSONObject: contactsStr, options: [])
let jsonString = try? String(data: data!, encoding: String.Encoding.utf8)
print(jsonString)
}
I am getting the output like this
[\n \"{\\\"phone\\\":\\\"+XXXX\\\",\\\"name\\\":\\\"YYYY\\\",\\\"email\\\":\\\"\\\"},\",\n \".........\n]
Please help me to do it in a better and clean way
Thanks for your help

I think you are double serializing your output. That's why I asked for the contact string.
Try:
func toJson() -> [String: AnyObject] {
var dict : [String: AnyObject] = [:]
dict["name"] = (self.name ?? "") as AnyObject
dict["phone"] = (self.phone ?? "") as AnyObject
dict["email"] = (self.email ?? "") as AnyObject
return dict
}
With:
var contactsStr = [[String: AnyObject]]()
And print out the serialization. It should just be singly escaping quotes such as \"name\". Not \\"name\\"

Related

swift how to add dictionary keys values in array

I am working on swift json Parsing where i am recieving json Data from Rest API for eg:
{"baseUrl":"http:\/\/localhost:9010\/",
"pluginOptions":{"values":[{"StartSyncTime":"2020-10-06 17:22:34","uuid":"977a5d03-2cdf-4008-87e6-01594e4369ef","LastSyncTime":"2020-10-06",
"MessageWrapper":{"Routing":"OriginSession","SourceSystem":"Mobile","MessageId":"51152ccd-32c6-475b-86a6-a2c883d551f5",
"UserID":"77ee794e-433d-4b93-bcaa-53408ede50fd","TenantID":"null","TenantName":"visurtest","Payload":"{}",
"DataType":"SQLLiteDDLAsync","MessageKind":"READ"}}],
"database":"structionDB","encrypted":false,"mode":"no-encryption"}}
I am getting as type [String:Any?] from rest api in below code
var pluginOptions : [String: Any]? = call.getObject("pluginOptions")
pluginOptions?[MessageWrapperKeys.DataType] = [DataTypes.SQLLiteDDLAsync]
pluginOptions?[MessageWrapperKeys.MessageKind] = [MessageKinds.READ]
pluginOptions?[MessageWrapperKeys.Payload] = ["{}"]
from above Json Response i need to extract MessageWrapper Dictionary like below
{"Routing":"OriginSession","SourceSystem":"VisurMobile","MessageId":"51152ccd-32c6-475b-86a6-a2c883d551f5",
"UserID":"77ee794e-433d-4b93-bcaa-53408ede50fd","TenantID":"null","TenantName":"visurtest","Payload":"{}",
"DataType":"SQLLiteDDLAsync","MessageKind":"READ"}
where above last 3 key vale i have added from code,Now i have to send Rest Api Call with above request but i did not able to figure it out how i will extraxt MessageWrapper Keys and append above 3 Key Values so that i get final jsonString Request like
{"Routing":"OriginSession","SourceSystem":"Mobile","MessageId":"05086b82-3623-492b-926a-d3bb8d01aa52","UserID":"77ee794e-433d-4b93-bcaa-53408ede50fd","TenantID":"null","TenantName":"test","Payload":"{}","DataType":"SQLLiteDDLAsync","MessageKind":"READ"}
below code i have triyed but not able to access
func readTableFromBackend(_ call: CAPPluginCall) -> Observable<String>{
var swrapper: [[String: Any]] = [[:]]
var pluginOptions : [String: Any]? = call.getObject("pluginOptions")
let json = JSON(pluginOptions)
var arrayNames = json["values"].arrayValue.map {$0["MessageWrapper"].string}
for arrayvalues in json["values"].arrayValue{
for arrayvalues in json["MessageWrapper"].arrayValue{
var string = arrayvalues["UserID"].string
}
var string = arrayvalues["MessageWrapper"].string
print(string)
}
pluginOptions?[MessageWrapperKeys.DataType] = [DataTypes.SQLLiteDDLAsync]
pluginOptions?[MessageWrapperKeys.MessageKind] = [MessageKinds.READ]
pluginOptions?[MessageWrapperKeys.Payload] = ["{}"]
var values = pluginOptions?["values"]
var modes = pluginOptions?["mode"]
for (key,value)in pluginOptions ?? ["":""]{
print("\(key) -> \(value)")
}
var finajsonstring: String = ""
var pluginOptions1: [String:Any] = [MessageWrapperKeys.DataType:DataTypes.SQLLiteDDLAsync, MessageWrapperKeys.MessageKind:MessageKinds.READ,MessageWrapperKeys.Payload: "{}"]
swrapper.append(pluginOptions ?? ["":""])
swrapper.append(pluginOptions1 )
let apidata = PullBackendData()
let plugindata = PluginCallParameterOptions()
var url: String? = call.getString("baseUrl")
// let payload = swrapper
let address = plugindata.getApiUrl(controllerName: Controllers.DataSync, baseUrl: url ?? "")
let jsonData = try? JSONSerialization.data(withJSONObject: pluginOptions)
guard let jsonString = String(data : jsonData!, encoding: .utf8
) else { return Observable.just("Error")}
let data = Data(jsonString.utf8)
do{
let newdata : NSDictionary = try JSONSerialization.jsonObject(with: data, options: []) as! NSDictionary
}
if((newdata.value(forKey: "values")) != nil){
let info : NSArray = newdata.value(forKey: "values") as! NSArray
let info1 : NSArray = info.value(forKey: "MessageWrapper") as! NSArray
var wrapperarray: [[String:Any]] = [[String:Any]]()
wrapperarray = newdata.value(forKey: "values") as! [[String:Any]]
wrapperarray.append(pluginOptions1)
let jsonData: NSData = try JSONSerialization.data(withJSONObject: info1, options: []) as NSData
let jsonData2: NSData = try JSONSerialization.data(withJSONObject: wrapperarray, options: []) as NSData
do {
var jsonstring = try NSString(data: jsonData as Data, encoding: String.Encoding.utf8.rawValue)! as String
var jsonstring2 = NSString(data: jsonData2 as Data, encoding: String.Encoding.utf8.rawValue)! as String
//getting final string and sending to rest api
finajsonstring = jsonstring2 as String
}catch {
print("error")
}
}
} catch let error as NSError{
print(error)
}
let response = apidata.post(_for: address, bodyData: finajsonstring)
return Observable.from(optional: response)
}

Reloading new JSON data swift

I am working on a project in swift where I need to write data to a JSON file, print that data, and be able to add more data as it arrives. At the moment, I can write to the JSON and display the first inputted data but after I add more and attempt to display it again, it just prints the new data.
I am using textView to display the data and using textFields and textView to get the data.
The code below should give you a better understanding.
#IBAction func addWords(_ sender: UIButton) {
let data: [String:String] = [
"Name": nameField.text ?? "N/A",
"Definition": defView.text ?? "N/A",
"Part of Speech": posField.text ?? "N/A"
]
let fileUrl = Bundle.main.url(forResource: "data", withExtension: "json")!
if let jsonData = try? JSONSerialization.data(withJSONObject: data, options: []) {
try! jsonData.write(to: fileUrl)
nameField.text = ""
defView.text = ""
posField.text = ""
} else {
print("Failed to save")
}
}
#IBAction func loadData(_ sender: UIButton) {
let fileUrl = Bundle.main.url(forResource: "data", withExtension: "json")!
let responseData: Data? = try! Data(contentsOf: fileUrl)
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)
textView.text = ("Name: \(name) (\(pos))\n Definition: \(definition)\n ")
}
}
}
}
}
'''

Parsing string json in swift 3

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

TableView Json Swift

I currently developing an app which list user object by making an request to a webservice, which send a response in JSON in this format :
{
"0":
{
"id":"30",
"title":"galaxys6",
"price":"550",
"description":"neuf",
"addedDate":"2015-07-16 15:04:24",
"user_id":"2",
"user_name":"",
"user_zipCode":"69003",
"category_id":"1",
"category_label":"PHONE",
"subcategory_id":"1",
"subcategory_label":"Phone",
"picture":"",
"bdd":{},
"picture_url":"http:\/\/jdl-barreme-orange.dyndns.org\/WEBSERVICE\/pictures\/galaxy s6.JPG"
},
"1":
{
"id":"31",
"title":"iphone4",
"price":"570",
"description":"neuf",
"addedDate":"2015-07-16 15:14:54",
"user_id":"2",
"user_name":"",
"user_zipCode":"69003",
"category_id":"1",
"category_label":"PHONE",
"subcategory_id":"1",
"subcategory_label":"Phone",
"picture":"",
"bdd":{},
"picture_url":"http:\/\/jdl-barreme-orange.dyndns.org\/WEBSERVICE\/pictures\/iphone.JPG"
},
}
For each object my webservice create a dictionary (0;1;2;3....)
I search a method to retrieve for each dictionary the value title and price and put them in a tableView.
Code I used (tableviewcontroller) :
if let jsonData:NSDictionary = NSJSONSerialization.JSONObjectWithData(urlData!, options:NSJSONReadingOptions.MutableContainers , error: &error) as? NSDictionary{
// 4
if let resp = jsonData["1"] as? [NSDictionary] {
NSLog("%#", resp)
// 5
for item in resp {
repositories.append(Repository(jsonData: item))
}
repository controller :
class Repository {
var name: String?
var description: String?
var html_url: String?
init(jsonData: NSDictionary) {
self.name = jsonData["id"] as? String
self.description = jsonData["description"] as? String
self.html_url = jsonData["title"] as? String
}
}
But it doesn't work, I put a breakpoint, and xcode stop to interpret here :
if let resp = jsonData["1"] as? [NSDictionary] {
NSLog("%#", resp)
What am I doing wrong?
Thank you.
Here's how to get the title and price for your JSON:
if let json = NSJSONSerialization.JSONObjectWithData(urlData!, options: nil, error: nil) as? [String:AnyObject] {
for (_, value) in json {
if let dict = value as? [String:AnyObject] {
if let title = dict["title"] as? String {
println(title)
}
if let price = dict["price"] as? String {
println(price)
}
}
}
}
This can also be used to init your Repository classes if you want:
class Repository {
var name: String?
var description: String?
var html_url: String?
init(jsonData: [String:AnyObject]) {
self.name = jsonData["id"] as? String
self.description = jsonData["description"] as? String
self.html_url = jsonData["title"] as? String
}
}
var repos = [Repository]()
if let json = NSJSONSerialization.JSONObjectWithData(urlData!, options: nil, error: nil) as? [String:AnyObject] {
for (_, value) in json {
if let dict = value as? [String:AnyObject] {
let repo = Repository(jsonData: dict)
repos.append(repo)
}
}
}
for repo in repos {
println(repo.name)
println(repo.description)
println(repo.html_url)
}
In the loop I'm ignoring the key: for (_, value) in json but you can use it if needed of course:
for (key, value) in json {
println(key) // "1", "2", ...
// ...
}
UPDATE:
Following your comment asking how to use this answer if your data format is different: if you want an array of dictionaries, change the typecast of the NSJSONSerialization result to reflect that: [[String:AnyObject]]. Next you can iterate over your array to get each dictionary properties:
if let jsonArray = NSJSONSerialization.JSONObjectWithData(urlData!, options: nil, error: nil) as? [[String:AnyObject]] {
for dict in jsonArray {
if let title = dict["title"] as? String {
println(title)
}
}
}
You are making a mistake here
if let resp = jsonData["1"] as? [NSDictionary]
This should be a NSDictionary not [NSDictionary], (which would be an array of dictionaries).
Also this conditional block
if let reposArray = jsonData["items"] as? [NSDictionary]
will never be executed because jsonData does not contain a key "items".
I guess it is the [NSDictionary]
if let resp = jsonData["1"] as? [NSDictionary]
[NSDictionary] is array of NSDictionary same as Array<NSDictionary>
just remove the brackets [] and change to
if let resp = jsonData["1"] as? NSDictionary

Parse json in Swift, AnyObject type

I'm trying to parse a json but I have some difficulties with the data types and notably the AnyObject type + downcasting.
Let's consider the following json (it's an extract of a full json).
{ "weather":
[
{
"id":804,
"main":"Clouds",
"description":"overcast clouds",
"icon":"04d"
}
],
}
To me, the json can be described as follow :
- json: Dictionary of type [String: AnyObject] (or NSDictionary, so = [NSObject, AnyObject] in Xcode 6 b3)
- "weather": Array of type [AnyObject] (or NSArray)
- Dictionary of type [String: AnyObject] (or NSDictionary, so = [NSObject, AnyObject] in Xcode 6 b3)
My json is of type AnyObject! (I use JSONObjectWithData to get the JSON from a URL).
I then want to access the weather Dictionary. Here is the code I wrote.
var localError: NSError?
var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &localError)
if let dict = json as? [String: AnyObject] {
if let weatherDictionary = dict["weather"] as? [AnyObject] {
// Do stuff with the weatherDictionary
}
}
Here is the error I got
Playground execution failed: error: <EXPR>:28:56: error: '[AnyObject]' is not a subtype of '(String, AnyObject)'
if let weatherDictionary = dict["weather"] as? [AnyObject] {
I don't understand why dict["weather"] is compared to a subtype of (String, AnyObject) and not AnyObject.
I declared my dictionary as [String: AnyObject], so I i access a value using the String key, I should have an AnyObject, no ?
If I use NSDictionary instead of [String: AnyObject], it works.
If I use NSArray instead of [AnyObject], it works.
- The Xcode 6 beta 3 release notes tell that "NSDictionary* is now imported from Objective-C APIs as [NSObject : AnyObject].".
- And the Swift book: "When you bridge from an NSArray object to a Swift array, the resulting array is of type [AnyObject]."
EDIT
I forgot to force unwrapping the dict["weather"]!.
if let dict = json as? [String: AnyObject] {
println(dict)
if let weatherDictionary = dict["weather"]! as? [AnyObject] {
println("\nWeather dictionary:\n\n\(weatherDictionary)")
if let descriptionString = weatherDictionary[0]["description"]! as? String {
println("\nDescription of the weather is: \(descriptionString)")
}
}
}
Note that we should double check for the existence of the first Optional.
if let dict = json as? [String: AnyObject] {
for key in ["weather", "traffic"] {
if let dictValue = dict[key] {
if let subArray = dictValue as? [AnyObject] {
println(subArray[0])
}
} else {
println("Key '\(key)' not found")
}
}
}
This works fine for me in the playground and in the terminal using env xcrun swift
UPDATED FOR SWIFT 4 AND CODABLE
Here is a Swift 4 example using the Codable protocol.
var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}"
struct Weather: Codable {
let id: Int
let main: String
let description: String
let icon: String
}
struct Result: Codable {
let weather: [Weather]
}
do {
let weather = try JSONDecoder().decode(Result.self, from: jsonStr.data(using: .utf8)!)
print(weather)
}
catch {
print(error)
}
UPDATED FOR SWIFT 3.0
I have updated the code for Swift 3 and also showed how to wrap the parsed JSON into objects. Thanks for all the up votes!
import Foundation
struct Weather {
let id: Int
let main: String
let description: String
let icon: String
}
extension Weather {
init?(json: [String: Any]) {
guard
let id = json["id"] as? Int,
let main = json["main"] as? String,
let description = json["description"] as? String,
let icon = json["icon"] as? String
else { return nil }
self.id = id
self.main = main
self.description = description
self.icon = icon
}
}
var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}"
enum JSONParseError: Error {
case notADictionary
case missingWeatherObjects
}
var data = jsonStr.data(using: String.Encoding.ascii, allowLossyConversion: false)
do {
var json = try JSONSerialization.jsonObject(with: data!, options: [])
guard let dict = json as? [String: Any] else { throw JSONParseError.notADictionary }
guard let weatherJSON = dict["weather"] as? [[String: Any]] else { throw JSONParseError.missingWeatherObjects }
let weather = weatherJSON.flatMap(Weather.init)
print(weather)
}
catch {
print(error)
}
-- Previous Answer --
import Foundation
var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}"
var data = jsonStr.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
var localError: NSError?
var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &localError)
if let dict = json as? [String: AnyObject] {
if let weather = dict["weather"] as? [AnyObject] {
for dict2 in weather {
let id = dict2["id"]
let main = dict2["main"]
let description = dict2["description"]
println(id)
println(main)
println(description)
}
}
}
Since I'm still getting up-votes for this answer, I figured I would revisit it for Swift 2.0:
import Foundation
var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}"
var data = jsonStr.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
do {
var json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)
if let dict = json as? [String: AnyObject] {
if let weather = dict["weather"] as? [AnyObject] {
for dict2 in weather {
let id = dict2["id"] as? Int
let main = dict2["main"] as? String
let description = dict2["description"] as? String
print(id)
print(main)
print(description)
}
}
}
}
catch {
print(error)
}
The biggest difference is that the variable json is no longer an optional type and the do/try/catch syntax. I also went ahead and typed id, main, and description.
Try:
https://github.com/dankogai/swift-json
With it you can go like this:
let obj:[String:AnyObject] = [
"array": [JSON.null, false, 0, "", [], [:]],
"object":[
"null": JSON.null,
"bool": true,
"int": 42,
"double": 3.141592653589793,
"string": "a α\t弾\n𪚲",
"array": [],
"object": [:]
],
"url":"http://blog.livedoor.com/dankogai/"
]
let json = JSON(obj)
json.toString()
json["object"]["null"].asNull // NSNull()
json["object"]["bool"].asBool // true
json["object"]["int"].asInt // 42
json["object"]["double"].asDouble // 3.141592653589793
json["object"]["string"].asString // "a α\t弾\n𪚲"
json["array"][0].asNull // NSNull()
json["array"][1].asBool // false
json["array"][2].asInt // 0
json["array"][3].asString // ""
Using my library (https://github.com/isair/JSONHelper) you can do this with your json variable of type AnyObject:
var weathers = [Weather]() // If deserialization fails, JSONHelper just keeps the old value in a non-optional variable. This lets you assign default values like this.
if let jsonDictionary = json as? JSONDictionary { // JSONDictionary is an alias for [String: AnyObject]
weathers <-- jsonDictionary["weather"]
}
Had your array not been under the key "weather", your code would have been just this:
var weathers = [Weather]()
weathers <-- json
Or if you have a json string in your hands you can just pass it as well, instead of creating a JSON dictionary from the string first. The only setup you need to do is writing a Weather class or struct:
struct Weather: Deserializable {
var id: String?
var name: String?
var description: String?
var icon: String?
init(data: [String: AnyObject]) {
id <-- data["id"]
name <-- data["name"]
description <-- data["description"]
icon <-- data["icon"]
}
}