How to loop through JSON data in SwiftyJSON - ios

I have a JSON data with structure and I don't know how to use for-loop with SwiftyJSON to get each sections entries of "path" and "updated" value. Anyone can help? Thanks.
var jsonData = "{
"css":[
{
"path": "style.css",
"updated": "12432"
},
{
"path": "base.css",
"updated": "34627"
},
],
"html":[
{
"path": "home.htm",
"updated": "3223"
},
{
"path": "about",
"updated": "3987"
}
]
}
"
I tried to code part of for-loop
let json = JSON(jsonData)
for ( ) in json {
let filepath =
let updated =
// do searching another json to found file exists and updates
}

It's on the README, under the section named "loop": https://github.com/SwiftyJSON/SwiftyJSON#loop
// If json is .Dictionary
for (key,subJson):(String, JSON) in json {
//Do something you want
}
// If json is .Array
// The `index` is 0..<json.count's string value
for (index,subJson):(String, JSON) in json {
//Do something you want
}
Applied to your specific JSON structure:
let jsonData = """
{
"css": [
{
"path": "style.css",
"updated": "12432"
},
{
"path": "base.css",
"updated": "34627"
}
],
"html": [
{
"path": "home.htm",
"updated": "3223"
},
{
"path": "about",
"updated": "3987"
}
]
}
""".data(using: .utf8)!
let json = JSON(data: jsonData)
for (_, subJson):(String, JSON) in json {
for (_, subJson):(String, JSON) in subJson {
let filepath = subJson["path"].stringValue
let updated = subJson["updated"].stringValue
print(filepath + " ~ " + updated)
}
}
Using Swift 4 Codable:
struct FileInfo: Decodable {
let path, updated: String
}
let dec = try! JSONDecoder().decode([String:[FileInfo]].self,from: jsonData)
print(dec)

As per your JSON structure, use this :
for (index,subJson):(String, JSON) in json {
print(index) // this prints "css" , "html"
for (key,subJson):(String, JSON) in subJson {
let filepath = subJson["path"]
let updated = subJson["updated"]
}
}

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

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

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

Unable to parse array of dictionary inside string

Currently I am working on bus booking module. After user set his departure and arrival city and date of journey, user will be shown a list of available buses. I have done that part successfully. But the problem which I am facing is that, each bus has it's own cancellation policy which is array of dictionary inside string. I am unable to parse it. Inside every dictionary of "apiAvailableBuses" there is "cancellationPolicy" key which has string as value which contains array of dictionary. I have removed other key value pairs from "apiAvailableBuses".
List of available Buses JSON response:
"apiAvailableBuses":[
{
"cancellationPolicy":"[{\"cutoffTime\":\"5\",\"refundInPercentage\":\"90\"}]"
},
{
"cancellationPolicy":"[{\"cutoffTime\":\"9-12\",\"refundInPercentage\":\"25\"},{\"cutoffTime\":\"12-24\",\"refundInPercentage\":\"35\"},{\"cutoffTime\":\"24-48\",\"refundInPercentage\":\"50\"},{\"cutoffTime\":\"48-60\",\"refundInPercentage\":\"75\"},{\"cutoffTime\":\"60\",\"refundInPercentage\":\"90\"}]"
},
{
"cancellationPolicy":"[{\"cutoffTime\":\"5\",\"refundInPercentage\":\"90\"}]"
},
{
"cancellationPolicy":"[{\"cutoffTime\":\"5\",\"refundInPercentage\":\"90\"}]"
},
{
"cancellationPolicy":"[{\"cutoffTime\":\"5\",\"refundInPercentage\":\"90\"}]"
},
{
"cancellationPolicy":"[{\"cutoffTime\":\"5\",\"refundInPercentage\":\"90\"}]"
},
{
"cancellationPolicy":"[{\"cutoffTime\":\"5\",\"refundInPercentage\":\"90\"}]"
},
{
"cancellationPolicy":"[{\"cutoffTime\":\"6-24\",\"refundInPercentage\":\"70\"},{\"cutoffTime\":\"24\",\"refundInPercentage\":\"85\"}]"
}
]
Can anyone help me with a solution for this? If anyone can't understand my question please let me know.
Note: I am not using Codable in my project.
Thanks in advance.
Use Codable to parse the above JSON response.
If your JSON response have the below format:
{
"apiAvailableBuses": [
{
"cancellationPolicy": [
{
"cutoffTime": "5",
"refundInPercentage": "90"
}
]
}
]
}
Create Codable types to parse the above response.
struct AvailableBuses: Codable {
var apiAvailableBuses: [Bus]
}
struct Bus: Codable {
var cancellationPolicy: [CancellationPolicy]
}
struct CancellationPolicy: Codable {
var cutoffTime: String
var refundInPercentage: String
}
In the above code, I've created 3 struct conforming to Codable protocol - AvailableBuses, Bus, CancellationPolicy
Usage:
After getting data from your API response, you can parse the it using the above created structs like,
if let data = jsonStr.data(using: .utf8) {
do {
let availableBuses = try JSONDecoder().decode(AvailableBuses.self, from: data)
print(availableBuses)
} catch {
print(error)
}
}
If you don't want to use Codable for some reason, you can use JSONSerialization.
let input = "[{\"cutoffTime\":\"5\",\"refundInPercentage\":\"90\"}]"
let data = input.data(using: .utf8)!
let parsed = try! JSONSerialization.jsonObject(with: data, options: []) as! Array<Dictionary<String, Any>>
print(parsed) // [["refundInPercentage": 90, "cutoffTime": 5]]
You can parse JSON string using the following method:
// JSON Format
let jsonResponse = ["apiAvailableBuses": [
[
"cancellationPolicy": "[{\"cutoffTime\":\"5\",\"refundInPercentage\":\"90\"}]"
],
[
"cancellationPolicy": "[{\"cutoffTime\":\"9-12\",\"refundInPercentage\":\"25\"},{\"cutoffTime\":\"12-24\",\"refundInPercentage\":\"35\"},{\"cutoffTime\":\"24-48\",\"refundInPercentage\":\"50\"},{\"cutoffTime\":\"48-60\",\"refundInPercentage\":\"75\"},{\"cutoffTime\":\"60\",\"refundInPercentage\":\"90\"}]"
],
[
"cancellationPolicy": "[{\"cutoffTime\":\"5\",\"refundInPercentage\":\"90\"}]"
],
[
"cancellationPolicy": "[{\"cutoffTime\":\"5\",\"refundInPercentage\":\"90\"}]"
],
[
"cancellationPolicy": "[{\"cutoffTime\":\"5\",\"refundInPercentage\":\"90\"}]"
],
[
"cancellationPolicy": "[{\"cutoffTime\":\"5\",\"refundInPercentage\":\"90\"}]"
],
[
"cancellationPolicy": "[{\"cutoffTime\":\"5\",\"refundInPercentage\":\"90\"}]"
],
[
"cancellationPolicy": "[{\"cutoffTime\":\"6-24\",\"refundInPercentage\":\"70\"},{\"cutoffTime\":\"24\",\"refundInPercentage\":\"85\"}]"
]
]
]
// Function Calling
setBuses(json: jsonResponse)
// Function to Parse JSON
func setBuses(json: Dictionary<String,Any>) {
guard let buses = json["apiAvailableBuses"] as? [Dictionary<String,Any>] else { return }
for (index, bus) in buses.enumerated() {
print("\n\nBus #\(index+1)")
guard let policies = convertToDictionary(text: bus["cancellationPolicy"] as! String) else { return }
for (index, policy) in policies.enumerated() {
print("\nPolicy #\(index+1)")
print("cutoffTime #\(index+1) \(String(describing: policy["refundInPercentage"]))")
print("refundInPercentage #\(index+1) \(String(describing: policy["cutoffTime"]))")
}
}
}
func convertToDictionary(text: String) -> [Dictionary<String,Any>]? {
let data = text.data(using: .utf8)!
do {
if let jsonObj = try JSONSerialization.jsonObject(with: data, options : .allowFragments) as? [Dictionary<String,Any>] {
return jsonObj
} else {
print("JSON Error")
}
} catch let error as NSError {
print(error)
}
return nil
}

swift getting all values of a dictionary and passing to viewcontroller using almaofire

Hi have an application which collects data from an api and I use Alamofire and swiftyJSON. the current challenge I am facing now is that I have different dictionaries in one array and I want to be able to retun back specific items in the dictionary. this is the array I am working with
Json
[
{
"images": [
{
"id": 8,
"original": "http://127.0.0.1:8000/media/images/products/2018/05/f3.jpg",
"caption": "",
"display_order": 0,
"date_created": "2018-05-26T17:24:34.762848Z",
"product": 13
},
{
"id": 9,
"original": "http://127.0.0.1:8000/media/images/products/2018/05/f5.jpg",
"caption": "",
"display_order": 1,
"date_created": "2018-05-26T17:24:34.815214Z",
"product": 13
},
{
"id": 10,
"original": "http://127.0.0.1:8000/media/images/products/2018/05/f2.jpg",
"caption": "",
"display_order": 2,
"date_created": "2018-05-26T17:25:19.117271Z",
"product": 13
},
{
"id": 11,
"original": "http://127.0.0.1:8000/media/images/products/2018/05/f4.jpg",
"caption": "",
"display_order": 3,
"date_created": "2018-05-26T17:25:19.155159Z",
"product": 13
}
]
}
]
get a single image is like this
Alamofire.request(URL, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: HEADER).responseJSON { (response) in
if response.result.error == nil {
guard let data = response.data else {return}
do {
if let json = try JSON(data: data).array {
for item in json {
let images = item["images"][0]["original"].stringValue
....
this returns only the indexed image.[0] if it is set to [1] it returns the indexed image at 1.
how do I return all the images so that I can loop through all and display in a collection view controller. more codes would be supplied on request.
You can dit it Like that :
if let json = try? JSON(data: data).arrayValue {
for item in json {
let imagesList = item["images"].arrayValue
let imagesURL = imagesList.map {$0["original"].string}.compactMap({$0})
if imagesURL.count > 0{
print( imagesURL[0])
}
}
}
Or:
do {
let json = try JSON(data: data).array
json?.forEach({ (item) in
let imagesList = item["images"].arrayValue
let imagesURL = imagesList.map {$0["original"].string}.compactMap({$0})
if imagesURL.count > 0{
print( imagesURL[0])
}
})
} catch {
print(error.localizedDescription)
}

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.

Resources