Create extension in Swift 5 for Dictonary[String:Any] - ios

I want to create extension for Dictionary [String:Any] which is received from API Response.
Right Now I am doing below way
I have created func getDataFromJson this is working fine, Please let me know how to do that.
func getDataFromJson(json: AnyObject) -> Data?{
do {
print("json = \(json)")
return try JSONSerialization.data(withJSONObject: json, options: JSONSerialization.WritingOptions.prettyPrinted)
} catch let myJSONError {
print("\n\n\nError => getDataFromJson => \(myJSONError)")
}
return nil;
}
This is my response and I want to "data" to Data
{
"status": true,
"message": "Country List",
"data": [
{
"id": 1,
"name": “ABC”,
"code": "A",
"phone_code": "+91”,
"flag": "country-flags/-shiny.png"
},
{
"id": 2,
"name": “ZYX”,
"code": “Z”,
"phone_code": "+1”,
"flag": "country-flags/-shiny.png"
}
]
}
I want to get data this way jsonResponse["data"].retriveData()

Here is a simple function that encodes the dictionary, the function throws any error so it can be properly handled. Since JSONSerialization.data(withJSONObject: takes an Any parameter this function can also be implemented for an array etc
extension Dictionary {
func retriveData() throws -> Data {
return try JSONSerialization.data(withJSONObject: self)
}
}
Simple example
let dict = ["abc": 123, "def": 456]
do {
let data = try dict.retriveData()
let result = try JSONDecoder().decode([String:Int].self, from:data)
print(result)
} catch {
print(error)
}
Another way is to use Result if you're on Swift 5 (shortened after comment from vadian)
extension Dictionary {
func retriveData() -> Result<Data, Error> {
return Result { try JSONSerialization.data(withJSONObject: self) }
}
}
and an example
let result = try dict.retriveData()
switch result {
case .success(let data):
let dictionary = try JSONDecoder().decode([String:Int].self, from:data)
print(dictionary)
case .failure(let error):
print(error)
}

a copy of your function transposed to an extension can be
extension Dictionary {
func retriveData() -> Data? {
do {
return try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
} catch let myJSONError {
print("\n\n\nError => getDataFromJson => \(myJSONError)")
}
return nil
}
}

Correct json
{
"status": true,
"message": "Country List",
"data": [
{
"id": 1,
"name": "ABC",
"code": "A",
"phone_code": "+91",
"flag": "country-flags/-shiny.png"
},
{
"id": 2,
"name": "ZYX",
"code": "Z",
"phone_code": "+1",
"flag": "country-flags/-shiny.png"
}
]
}
Model
struct Datum: Codable {
let id: Int
let name, code, phoneCode, flag: String
}
Decoding data only
let str = """
{
"status": true,
"message": "Country List",
"data": [{
"id": 1,
"name": "ABC",
"code": "A",
"phone_code": "+91",
"flag": "country-flags/-shiny.png"
},
{
"id": 2,
"name": "ZYX",
"code": "Z",
"phone_code": "+1",
"flag": "country-flags/-shiny.png"
}
]
}
"""
do {
let dic = try JSONSerialization.jsonObject(with: Data(str.utf8)) as! [String:Any]
let content = try JSONSerialization.data(withJSONObject: dic["data"])
let dec = JSONDecoder()
dec.keyDecodingStrategy = .convertFromSnakeCase
let res = try dec.decode([Datum].self, from: content)
print(res)
}
catch {
print(error)
}

Please try this
// Response Dictionary
let jsonResponse : [String:Any] = ["data":["key1":"value1",
"key2":"value2",
"key3":"value3",
"key4":"value4"]]
// check dictionary contains value for key "data"
if let dataDict = jsonResponse["data"] as? [String:Any] {
// convert dictionary to data
let jsonData = dataDict.retriveData()
print("Json Data :- ", jsonData != nil ? "Success" : "Data is nil")
}
// Dictionary exxtension for converting dictionary to json data
extension Dictionary {
func retriveData() -> Data? {
do {
print("json = \(self)")
return try JSONSerialization.data(withJSONObject: self, options: JSONSerialization.WritingOptions.prettyPrinted)
} catch let myJSONError {
print("\n\n\nError => getDataFromJson => \(myJSONError)")
}
return nil;
}
}

Related

How to parse grouped nested dictionary in swift

Please help me out for parsing the below json response in SWIFT5 as I am getting nil values for the user and group data.
{
"user": {
"0": {
"id": "5",
"name": "ABC"
}
},
"group": {
"0": {
"id": "510",
"name": "XYZ"
}
}
}
if let unwrappedData = data {
do{
let json = try JSONSerialization.jsonObject(with: unwrappedData, options: [])
print(json)
if let user = try? JSONDecoder().decode(UserModel.self,from:unwrappedData){
completion(.success(user))
}else{
let errorResponse = try JSONDecoder().decode(ErrorResponse.self, from: unwrappedData)
completion(.failure(errorResponse.errorValue))
}
}catch{
completion(.failure(error))
}
}
The user data is printing as nil. please help me out to resolve the issue.
I tried below code in playground and it works like charm, what is the issue in json?
Data Model
// MARK: - Sample
struct Sample: Codable {
let user, group: Group
}
// MARK: - Group
struct Group: Codable {
let the0: The0
enum CodingKeys: String, CodingKey {
case the0 = "0"
}
}
// MARK: - The0
struct The0: Codable {
let id, name: String
}
Json Data
let jsonData = """
{
"user": {
"0": {
"id": "5",
"name": "ABC"
}
},
"group": {
"0": {
"id": "510",
"name": "XYZ"
}
}
}
""".data(using: .utf8)
Json Parsing
if let data = jsonData {
let object = try? JSONDecoder().decode(Sample.self, from: data)
print("Json Object", object)
}
else {
print("Bad Json")
}
Output
Json Object Optional(SwiftPlayground.Sample(user: SwiftPlayground.Group(the0: SwiftPlayground.The0(id: "5", name: "ABC")), group: SwiftPlayground.Group(the0: SwiftPlayground.The0(id: "510", name: "XYZ"))))

assigning "Get" Request data to Text field

My get data response is like
I want "title" and "date" should be shown in my view controller "label values"
get method calls when app running and the data should display in either text fields "or" in label
My Code is
guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else { fatalError() }
let session = URLSession.shared
session.dataTask(with: url) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
print(data)
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
} catch {
print(error)
}
}
}.resume()
out put is :
[
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere#april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
},
{
"id": 2,
"name": "Ervin Howell",
"username": "Antonette",
"email": "Shanna#melissa.tv",
"address": {
"street": "Victor Plains",
"suite": "Suite 879",
"city": "Wisokyburgh",
"zipcode": "90566-7771",
"geo": {
"lat": "-43.9509",
"lng": "-34.4618"
}
},
]
I want to print "username":
"email":
values in my Storyboard labels
The result contains multiple users, so you should first iterate over them and find the user you want. Then you can set text on your UI elements in the Main thread.
guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else { fatalError() }
typealias User = [String: Any]
let session = URLSession.shared
session.dataTask(with: url) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
print(data)
do {
let usersJson = try JSONSerialization.jsonObject(with: data, options: []) as! [User]
print(usersJson)
// Since the result is an array of users
for user in usersJson {
guard let userName = user["username"] as? String else { return assertionFailure("Invalid username") }
print(userName)
// All UI works should done in main thread
DispatchQueue.main.async {
<#usernameLabel#>.text = username
}
}
} catch {
print(error)
}
}
}.resume()
I suggest you take a look at Swift Codable. It will boost your coding and minimize syntax and human errors.

how to show titles(Type) in table view using JSON Data in iOS Swift?

how to show titles(Type) in table view using JSON Data in iOS Swift using the following format
[
{
"Id": 11000,
"Type": "Title1"
},
{
"Id": 11001,
"Type": "Title2"
},
{
"Id": 11002,
"Type": "Title3"
},
{
"Id": 11003,
"Type": "Title4"
}
]
You can use the following function to read titles in an array and use it as data source for tableView.
private func readJson( data : Data) -> [String] {
var titlesArray = [String]()
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
if let jsonDict = json as? [[String: Any]] {
for anObject in jsonDict {
if let title = anObject["Type"] as? String {
titlesArray.append(title)
}
}
} else {
print("JSON is invalid")
}
} catch {
print(error.localizedDescription)
}
return titlesArray
}
I would suggest to use SwiftyJson for json parsing. Instead of doing it manually. You can read about Swifty Json.

Swift and JSON parsing only an object not an array

I am working on a weather app that parses JSON data and sets the text of my label to the temp value of the JSON request. I got the value of id from the weather object array, but the temp is not in an array it is just an object. Can someone please tell me where I am wrong. My value is reurning nil because I am not fetching it correctly. Here is my snippet and JSON.
#IBAction func getWeather(sender: AnyObject) {
let requestURL: NSURL = NSURL(string: "http://api.openweathermap.org/data/2.5/weather?lat=35&lon=139&appid=MYAPPID")!
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(urlRequest) {
(data, response, error) -> Void in
let httpResponse = response as! NSHTTPURLResponse
let statusCode = httpResponse.statusCode
if (statusCode == 200) {
print("JSON Downloaded Sucessfully.")
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
if let today = json["weather"] as? [[String: AnyObject]] {
//this is pulling 4 key value pairs
for weather in today {
//this works
let id = weather["id"]?.stringValue
self.trumpDescription.text=id;
print(id)
//this is where I am confused it changes from an array to just an object
let temp = json["temp"] as? String
self.currentTempView.text=temp;
print(temp)
}
}
}
catch {
print("Error with Json: \(error)")
}
}
}
task.resume()
}`
Here is the JSON:
{
"coord": {
"lon": 138.93,
"lat": 34.97
},
"weather": [
{
"id": 803,
"main": "Clouds",
"description": "broken clouds",
"icon": "04n"
}
],
"base": "cmc stations",
"main": {
"temp": 292.581,
"pressure": 1019.48,
"humidity": 99,
"temp_min": 292.581,
"temp_max": 292.581,
"sea_level": 1028.92,
"grnd_level": 1019.48
},
"wind": {
"speed": 5.36,
"deg": 237.505
},
"clouds": {
"all": 64
},
"dt": 1464964606,
"sys": {
"message": 0.0037,
"country": "JP",
"sunrise": 1464895855,
"sunset": 1464947666
},
"id": 1851632,
"name": "Shuzenji",
"cod": 200
}
It looks like it should be
if let main = json["main"] as? NSDictionary {
let temp = main["temp"] as! String
print(temp)
}
Instead of this:
let temp = json["temp"] as? String
Try this:
if let main = json["main"] as? [String: AnyObject] {
let temp = main[temp]?.stringValue
print(temp)
//alternatively you can try this as per your convenience of data type
let tempNew = main[temp]?.doubleValue
print(tempNew)
}

NSJSONSerialization return nil with a valid json

I try to parse a response which return a valid JSON with NSJSonSerialization. But it returns nil with no error. It works with another JSON response.
I did some search, and this could be a problem with the encoding of the JSON. I don't know how to solve it. Any idea ?
let url: NSURL = NSURL(string: urlPath)!
self.searchRequest = NSMutableURLRequest(URL: url)
if let searchRequest = self.searchRequest {
searchRequest.HTTPMethod = "GET"
let authString : String = SNCF.APIKey + ":" + ""
let authData : NSData = authString.dataUsingEncoding(NSASCIIStringEncoding)!
let authValue : String = "Basic " + authData.base64EncodedStringWithOptions(.EncodingEndLineWithCarriageReturn)
searchRequest.setValue(authValue, forHTTPHeaderField: "Authorization")
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(searchRequest, queue: queue, completionHandler:{ (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
do {
//HERE JSONRESULT WILL BE NIL
if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [String: [AnyObject]] {
print("ASynchronous\(jsonResult)")
if let places = jsonResult["stop_areas"] as? [[String:AnyObject]]{
for placeDictionary in places {
if let labelText = placeDictionary["label"] as? String {
self.resultDatasource.append(labelText)
}
}
self.resultTableView.reloadData()
}
}
//HERE NO ERROR IS CATCHED
} catch let error as NSError {
print(error.localizedDescription)
}
})
Piece of my json response :
{
"disruptions": [],
"pagination": {
"start_page": 0,
"items_on_page": 100,
"items_per_page": 100,
"total_result": 3053
},
"stop_areas": [
{
"codes": [
{
"type": "CR-CI-CH",
"value": "0080-251967-BV"
}
],
"name": "gare de Perl",
"links": [],
"coord": {
"lat": "0",
"lon": "0"
},
"label": "gare de Perl",
"timezone": "Europe/Paris",
"id": "stop_area:OCE:SA:80251967"
},
{
...
},
//stop_areas dictionaries object...
], //end stop_areas array of dictionaries
"links": [
{
"href": "https://api.sncf.com/v1/coverage/sncf/stop_areas/{stop_areas.id}",
"type": "stop_areas",
"rel": "stop_areas",
"templated": true
},
{
"href": "https://api.sncf.com/v1/coverage/sncf/stop_areas?start_page=1",
"type": "next",
"templated": false
},
{
"href": "https://api.sncf.com/v1/coverage/sncf/stop_areas?start_page=30.52",
"type": "last",
"templated": false
},
{
"href": "https://api.sncf.com/v1/coverage/sncf/stop_areas",
"type": "first",
"templated": false
}
],
"feed_publishers": [
{
"url": "",
"id": "sncf",
"license": "",
"name": ""
}
]
}
The type of the JSON is [String: AnyObject] not [String: [AnyObject]]
I think this is the problem:
as? [String: [AnyObject]]
Try to remove the cast. If your JSON is correct and has no validation errors, the dictionary you get probably has the key value of type Any. You can try to use the dictionary by only casting the value keys you want:
if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: nil) {
print("ASynchronous\(jsonResult)")
if let places = jsonResult["stop_areas"] as? [[String:AnyObject]] {
...
}
}
Try This
do {
if let jsonResult: Dictionary = try NSJSONSerialization.JSONObjectWithData(self.mutableData, options: NSJSONReadingOptions.MutableContainers) as? Dictionary<String, AnyObject>
{
// print("get Read messages == \(jsonResult)");
if ((jsonResult["Warning"]) != nil)
{
let error_by_wc: NSString = jsonResult["Warning"] as! String
//print("results == \(error_by_wc)");
// printMessage("\(error_by_wc)")
JLToast.makeText("\(error_by_wc)").show()
}else if((jsonResult["Error"]) != nil)
{
let error_by_wc: NSString = jsonResult["Error"] as! String
// print("results == \(error_by_wc)");
// printMessage("\(error_by_wc)")
JLToast.makeText("\(error_by_wc)").show()
}
else
{
// read message s
}
} catch {
print(error)
}
If Data is Array Type Use this code
do {
if let jsonResult:NSArray = try NSJSONSerialization.JSONObjectWithData(self.mutableData, options: .MutableContainers) as? NSArray {
//print(jsonResult)
aDataBase.insertFromUserImage(jsonResult)
connection_allMEssages()
}else
{
//print("not data found")
BProgressHUD.dismissHUD(0)
}
} catch {
print(error)
BProgressHUD.dismissHUD(0)
}

Resources