Club Values of array - ios

I am writing an iOS App in Swift 4.2.
I am geting JSON array which I convert into Swift object of Class Sector
JSON:
"Sector": [
{
"REPSECTOR": "TELECOM - SERVICES",
"PERC_HOLD": 5.6,
"CO_NAME": "REVERSE REPO"
},
{
"REPSECTOR": "TELECOM - SERVICES",
"PERC_HOLD": 1.0,
"CO_NAME": "BHARTI AIRTEL"
},
{
"REPSECTOR": "FERROUS METALS",
"PERC_HOLD": 0.3,
"CO_NAME": "COAL INDIA"
}
]
Class:
class Sector{
var REPSECTOR:String=""
var PERC_HOLD:Double=0.0
var CO_NAME:String=""
}
I am making Array array1 of type [Sector] from above.
I need to make a new array from above array which must be clubed/combined values based on REPSECTOR variable, and total of PERC_HOLD.
Expected Result:
new array with 2 elements:
1: TELECOM - SERVICES, 5.6+1.0
2: FERROUS METALS, 0.3

Suppose the array you've decoded is called array :
var array: [Sector]()
Let's create a dictionary of sectors that have the same REPSECTOR property :
let dict = Dictionary(grouping: array) {
$0.REPSECTOR
}
Now let's create an new array with sectors that have the same name, and sum their PERC_HOLD :
var newArray = [Sector]()
for (key, value) in dict {
let sector = Sector()
sector.REPSECTOR = key
sector.PERC_HOLD = value.reduce(0, { $0 + $1.PERC_HOLD })
newArray.append(sector)
}
You could check the result this way :
for s in newArray {
print(s.CO_NAME, s.PERC_HOLD)
}

First, I think you should use proper casing in your Sector type, and use Codable. For your type it would be trivial:
struct Sector: Codable {
let repsector: String
let percHold: Double
let coName: String
enum CodingKeys: String, CodingKey {
case repsector = "REPSECTOR"
case percHold = "PERC_HOLD"
case coName = "CO_NAME"
}
}
Then, assuming we have JSON like this:
let sectorsJSON = """
[
{
"REPSECTOR": "TELECOM - SERVICES",
"PERC_HOLD": 5.6,
"CO_NAME": "REVERSE REPO"
},
{
"REPSECTOR": "TELECOM - SERVICES",
"PERC_HOLD": 1.0,
"CO_NAME": "BHARTI AIRTEL"
},
{
"REPSECTOR": "FERROUS METALS",
"PERC_HOLD": 0.3,
"CO_NAME": "COAL INDIA"
}
]
""".data(using: .utf8)!
Then we can decode your JSON like this:
let decoder = JSONDecoder()
let rawSectors = try decoder.decode([Sector].self, from: sectorsJSON)
And then we can group it by .repsector and sum up percentages:
let groupedSectors = Dictionary(grouping: rawSectors, by: { $0.repsector })
.map { (arg) -> (String, Double) in
let (key, value) = arg
let percents = value.reduce(into: 0, { (acc, sector) in
acc += sector.percHold
})
return (key, percents)
}
print(groupedSectors) // [("FERROUS METALS", 0.3), ("TELECOM - SERVICES", 6.6)]

let dicSector = ["Sector": [
[
"REPSECTOR": "TELECOM - SERVICES",
"PERC_HOLD": 5.6,
"CO_NAME": "REVERSE REPO"
],
[
"REPSECTOR": "TELECOM - SERVICES",
"PERC_HOLD": 1.0,
"CO_NAME": "BHARTI AIRTEL"
],
[
"REPSECTOR": "FERROUS METALS",
"PERC_HOLD": 0.3,
"CO_NAME": "COAL INDIA"
]
]]
Codable Sector
class Sector: Codable {
var REPSECTOR:String=""
var PERC_HOLD:Double=0.0
var CO_NAME:String=""
}
Convert Dictonary to object array
var arraySector = [Sector]()
if let array = dicSector["Sector"] {
do {
let data = try JSONSerialization.data(withJSONObject: array, options: JSONSerialization.WritingOptions.prettyPrinted)
let jsonDecoder = JSONDecoder()
arraySector = try jsonDecoder.decode([Sector].self, from: data)
}
catch {
print(error.localizedDescription)
}
}
Array To Grouping
let predicate = { (element: Sector) in
return element.REPSECTOR
}
let dic = Dictionary(grouping: arraySector, by: predicate)
print(dic)
Output
["TELECOM - SERVICES": [Sector, Sector], "FERROUS
METALS": [Sector]]

This is not the best solution but working
var newArray = [Sector]()
oldArray.forEach() { element in
if newArray.contains(where: { $0.REPSECTOR == element.REPSECTOR }) {
newArray.forEach() { newElement in
if newElement.REPSECTOR == element.REPSECTOR {
newElement.CO_NAME + element.CO_NAME
} else {
newArray.append(element)
}
}
} else {
newArray.append(element)
}
}

Related

Custom JSON decoding: decode an array of different objects in several distinct arrays

I need your help to implement a custom JSON decoding. The JSON returned by the API is:
{
"zones": [
{
"name": "zoneA",
"blocks": [
// an array of objects of type ElementA
]
},
{
"name": "zoneB",
"blocks": [
// an array of objects of type ElementB
]
},
{
"name": "zoneC",
"blocks": [
// an array of objects of type ElementC
]
},
{
"name": "zoneD",
"blocks": [
// an array of objects of type ElementD
]
}
]
}
I don't want to parse this JSON as an array of zones with no meaning. I'd like to produce a model with an array for every specific type of block, like this:
struct Root {
let elementsA: [ElementA]
let elementsB: [ElementB]
let elementsC: [ElementC]
let elementsD: [ElementD]
}
How can I implement the Decodable protocol (by using init(from decoder:)) to follow this logic? Thank you.
This is a solution with nested containers. With the given (simplified but valid) JSON string
let jsonString = """
{
"zones": [
{
"name": "zoneA",
"blocks": [
{"name": "Foo"}
]
},
{
"name": "zoneB",
"blocks": [
{"street":"Broadway", "city":"New York"}
]
},
{
"name": "zoneC",
"blocks": [
{"email": "foo#bar.com"}
]
},
{
"name": "zoneD",
"blocks": [
{"phone": "555-01234"}
]
}
]
}
"""
and the corresponding element structs
struct ElementA : Decodable { let name: String }
struct ElementB : Decodable { let street, city: String }
struct ElementC : Decodable { let email: String }
struct ElementD : Decodable { let phone: String }
first decode the zones as nestedUnkeyedContainer then iterate the array and decode first the name key and depending on name the elements.
Side note: This way requires to declare the element arrays as variables.
struct Root : Decodable {
var elementsA = [ElementA]()
var elementsB = [ElementB]()
var elementsC = [ElementC]()
var elementsD = [ElementD]()
enum Zone: String, Decodable { case zoneA, zoneB, zoneC, zoneD }
private enum CodingKeys: String, CodingKey { case zones }
private enum ZoneCodingKeys: String, CodingKey { case name, blocks }
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
var zonesContainer = try container.nestedUnkeyedContainer(forKey: .zones)
while !zonesContainer.isAtEnd {
let item = try zonesContainer.nestedContainer(keyedBy: ZoneCodingKeys.self)
let zone = try item.decode(Zone.self, forKey: .name)
switch zone {
case .zoneA: elementsA = try item.decode([ElementA].self, forKey: .blocks)
case .zoneB: elementsB = try item.decode([ElementB].self, forKey: .blocks)
case .zoneC: elementsC = try item.decode([ElementC].self, forKey: .blocks)
case .zoneD: elementsD = try item.decode([ElementD].self, forKey: .blocks)
}
}
}
}
Decoding the stuff is straightforward
do {
let result = try JSONDecoder().decode(Root.self, from: Data(jsonString.utf8))
print(result)
} catch {
print(error)
}
the "zone" property is an array of Zone objects. so you can decode them like:
enum Zone: Decodable {
case a([ElementA])
case b([ElementB])
case c([ElementC])
case d([ElementD])
enum Name: String, Codable {
case a = "zoneA"
case b = "zoneB"
case c = "zoneC"
case d = "zoneD"
}
enum RootKey: CodingKey {
case name
case blocks
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: RootKey.self)
let zoneName = try container.decode(Name.self, forKey: .name)
switch zoneName {
case .a: try self = .a(container.decode([ElementA].self, forKey: .blocks))
case .b: try self = .b(container.decode([ElementB].self, forKey: .blocks))
case .c: try self = .c(container.decode([ElementC].self, forKey: .blocks))
case .d: try self = .d(container.decode([ElementD].self, forKey: .blocks))
}
}
}
Then you can filter out anything you like. For example you can pass in the array and get the result you asked in your question:
struct Root {
init(zones: [Zone]) {
elementsA = zones.reduce([]) {
guard case let .a(elements) = $1 else { return $0 }
return $0 + elements
}
elementsB = zones.reduce([]) {
guard case let .b(elements) = $1 else { return $0 }
return $0 + elements
}
elementsC = zones.reduce([]) {
guard case let .c(elements) = $1 else { return $0 }
return $0 + elements
}
elementsD = zones.reduce([]) {
guard case let .d(elements) = $1 else { return $0 }
return $0 + elements
}
}
let elementsA: [ElementA]
let elementsB: [ElementB]
let elementsC: [ElementC]
let elementsD: [ElementD]
}
✅ Benefits:
Retain the original structure (array of zones)
Handle repeating zones (if server sends more than just one for each zone)

Sorting & section in UItableview from JSON data

I have defined the data model for packages data, but need to define UITableview sections on the basis of
subscriptiontype = 'Yearly', 'Monthly', 'Weekly'
Getting an error of - Cannot assign value of type '[Package]' to type '[[String : String]]?'. How can I assign it to tableview sections.
Code:
var packag = [Package]()
enum TableSection: Int {
case subscriptionType = 0, yearly, monthly, weekly, total
}
var data = [TableSection: [[String: String]]]()
func sortData() {
data[.yearly] = packag.filter({ $0.subscriptionType == "yearly" })
data[.monthly] = packag.filter({ $0.subscriptionType == "monthly" })
data[.weekly] = packag.filter({ $0.subscriptionType == "weekly" })
}
Updated Code - viewdidload():
override func viewDidLoad() {
super.viewDidLoad()
tableview.dataSource = self
tableview.delegate = self
//fetchData()
if let path = Bundle.main.path(forResource: "packageList", ofType: "json") {
do {
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .custom{ decoder -> Date in
let container = try decoder.singleValueContainer()
let dateStr = try container.decode(String.self)
return Date(timeIntervalSince1970: TimeInterval(dateStr)!)
}
let jSON = try? decoder.decode(Root.self, from: data)
if let packages = jSON?.packages {
self.sortData(packages: packages)
print(packages)
}
} catch {
// handle error
print(Error.self)
}
}
}
Root Model:
struct Root : Codable {
let packages : [Package]
}
Packages Model:
struct Package : Codable {
let availableUntil : Date
let benefits : [String]?
let desc : String
let didUseBefore : Bool
let name : String
let price : Double
let subscriptionType : String
let tariff : Tariff
}
Traiff Model:
struct Tariff : Codable {
let data : String
let sms : String
let talk : String
}
Updated PackageJson Data:
{ "packages": [
{
"name": "Platinum Maksi 6 GB",
"desc": "Zengin içerikli Platinum Maksi Paketi ile Turkcell Uygulamalarının keyfini sürün!",
"subscriptionType": "monthly",
"didUseBefore": true,
"benefits": [
"TV+",
"Fizy",
"BiP",
"lifebox",
"Platinum",
"Dergilik"
],
"price": 109.90,
"tariff": {
"data": "6144",
"talk": "2000",
"sms": "100"
},
"availableUntil": "1558131150"
},
{
"name": "Platinum Maksi 8 GB",
"desc": "Zengin içerikli Platinum Maksi Paketi ile Turkcell Uygulamalarının keyfini sürün!",
"subscriptionType": "monthly",
"didUseBefore": false,
"benefits": [
"TV+",
"Fizy",
"BiP",
"lifebox",
"Platinum",
"Dergilik"
],
"price": 129.90,
"tariff": {
"data": "8192",
"talk": "2000",
"sms": "100"
},
"availableUntil": "1555060350"
},
{
"name": "Platinum Maksi 12 GB",
"desc": "Zengin içerikli Platinum Maksi Paketi ile Turkcell Uygulamalarının keyfini sürün!",
"subscriptionType": "yearly",
"didUseBefore": false,
"benefits": [
"TV+",
"Fizy",
"BiP",
"lifebox",
"Platinum",
"Dergilik"
],
"price": 109.90,
"tariff": {
"data": "12288",
"talk": "2000",
"sms": "100"
},
"availableUntil": "1555060350"
},
The problem is that you are trying to assign a Package object to a value that is expecting an array of dictionary.
Your data variable is a dictionary that has a TableSection as a key, and an array of dictionaries as the value which you have defined by writing [[String: String]]. Then in your sortData function you're trying to assign a value to various data keys, but you're assigning a Package item to it when it's expecting an array of dictionaries.
What will work is if you change your data definition to
var data = [TableSection: Package]()
Model
import Foundation
struct JSON: Codable {
let packages: [Package]
}
struct Package: Codable {
let name, desc, subscriptionType: String
let didUseBefore: Bool
let benefits: [String]
let price: Double
let tariff: Tariff
let availableUntil: String
}
struct Tariff: Codable {
let data, talk, sms: String
}
Enum
enum TableSection: Int {
case subscriptionType = 0, yearly, monthly, weekly, total
}
Data
var data = [TableSection: [Package]]()
Parsing
if let path = Bundle.main.path(forResource: "document", ofType: "json") {
do {
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
let jSON = try? JSONDecoder().decode(JSON.self, from: data)
if let packages = jSON?.packages {
self.sortData(packages: packages)
}
} catch {
// handle error
}
}
Sorting
private func sortData(packages : [Package]) {
data[.yearly] = packages.filter({ $0.subscriptionType == "yearly" })
data[.monthly] = packages.filter({ $0.subscriptionType == "monthly" })
data[.weekly] = packages.filter({ $0.subscriptionType == "weekly" })
print("Data is \(data)")
}
I use LOCAL JSON, you can use server data.

how to add Json value into model Array to display into tableview in swift

I'm using the tableview to display the Two Json value but the problem is I cant add value into model struct to displaying into tableview using two Api's. i want to show percentage value in one of the cell label and
here is my json
[
{
"Percentage": 99.792098999,
}
]
my second json value
{
"Categories": [
"Developer",
"ios "
],
"Tags": [
{
"Value": "kishore",
"Key": "Name"
},
{
"Value": "2",
"Key": "office"
},
]
}
and i need show the Categories value in Categories label in tableview
value and key on tableview
here is my Struct
struct info: Decodable {
let Categories: String?
let Tags: String?
let Value: String?
let Key: String?
var Name: String?
let percentage: Double?
}
here its my code
var List = [info]()
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
print(json as Any)
guard let jsonArray = json as? [[String: Any]] else {
return
}
print(jsonArray)
for dic in jsonArray{
guard let per = dic["percentage"] as? Double else { return }
print(per)
}
and second json
if let array = json["Tags"] as? [[String: String]] {
for dict in array {
let key = dict["Key"]
let value = dict["Value"]
switch key {
case "office":
case "Name":
default:
break;
}
}
here is my cell for row indexpath
cell.Categories.text = list[indexpath.row].percentage
cell.Name.text = list[indexpath.row].name
cell.office.text = list[indexpath.row].office
Please use Swift 4 Codable protocol to decode the value from JSON.
//1.0 Create your structures and make it conform to Codable Protocol
struct Tags: Codable{
var Key: String
var Value: String
}
struct Sample: Codable{
var Categories: [String]
var Tags: [Tags]
}
In your method, perform below steps:
//2.0 Get your json data from your API. In example below, i am reading from a JSON file named "Sample.json"
if let path = Bundle.main.path(forResource: "Sample", ofType: "json") {
do {
let jsonData = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
do {
//3.0 use JSONDecoder's decode method to decode JSON to your model.
let sample = try JSONDecoder().decode(Sample.self, from: jsonData)
//4.0 User the "sample" model to do your stuff. Example, printing some values
print("Sample.Category = \(sample.Categories)")
print("Sample.Name = \(sample.Tags[0].Value)")
print("Sample.Office = \(sample.Tags[1].Value)")
} catch let error {
print("Error = \(error)")
}
} catch {
// handle error
}
}
I prefer to use Codable all the time with JSON even for simpler types so for percentage I would do
struct ItemElement: Decodable {
let percentage: Double
enum CodingKeys: String, CodingKey {
case percentage = "Percentage"
}
}
and we need to keep these values in a separate array, declared as a class property
let percentageList: [Double]()
and json encoding would then be
let decoder = JSONDecoder()
do {
let result = try decoder.decode([ItemElement].self, from: data)
percentageList = result.map { item.percentage }
} catch {
print(error)
}
Similar for the second part
struct Item: Decodable {
let categories: [String]
let tags: [Tag]
enum CodingKeys: String, CodingKey {
case categories = "Categories"
case tags = "Tags"
}
}
struct Tag: Decodable {
let value, key: String
enum CodingKeys: String, CodingKey {
case value = "Value"
case key = "Key"
}
}
use a dictionary for the result, again as a class property
var values = [String: String]()
and the decoding
let decoder = JSONDecoder()
do {
let result = try decoder.decode(Item.self, from: data)
for item in result.tags {
values[item.key] = values.item.value
}
} catch {
print(error)
}
and then in the cell for row code
cell.Categories.text = percentageList[indexpath.row].percentage
cell.Name.text = values["name"]
cell.office.text = values["office"]
Note that this last code looks very strange since you don't have an array of name/office values judging by your json. Maybe you have simplified it some way but the code above is the best I can do with the information given even if it possibly wrong

How to extract JSON data from array inside of array in Swift 2.0

I am currently using Openweathermap.org to get weather forecast information. And here is the JSON objects I got from their API:
{
"city":{ },
"cod":"200",
"message":0.0029,
"cnt":40,
"list":[
{
"dt":1466532000,
"main":{
"temp":296.52,
"temp_min":294.864,
"temp_max":296.52,
"pressure":1004.95,
"sea_level":1023.45,
"grnd_level":1004.95,
"humidity":58,
"temp_kf":1.65
},
"weather":[
{
"id":803,
"main":"Clouds",
"description":"broken clouds",
"icon":"04d"
}
],
"clouds":{ },
"wind":{ },
"sys":{ },
"dt_txt":"2016-06-21 18:00:00"
},
{
"dt":1466542800,
"main":{ },
"weather":[ ],
"clouds":{ },
"wind":{ },
"sys":{ },
"dt_txt":"2016-06-21 21:00:00"
},
{
"dt":1466553600,
"main":{ },
"weather":[ ],
"clouds":{ },
"wind":{ },
"sys":{ },
"dt_txt":"2016-06-22 00:00:00"
}]
}
As you can see from this sample, under list there are many objects and what I want is just the temp and the weather main and description. I created a Struct to sort and hold all of the JSON objects but it keeps giving me errors. How do I sort it in terms of the "dt" and how would I extract the data from the JSON. Thanks.
Here is my Struct:
import Foundation
struct FutureWeather {
//future stuff
var futureDt: NSDate //
var futureMainWeather: String//
var futureDescription: String//
private var futureTemp: Double//
var futureTempCelsius: Double {
get {
return futureTemp - 273.15
}
}
var futureTempFahrenheit: Double {
get {
return (futureTemp - 273.15) * 1.8 + 32
}
}
init(futureWeatherData : [String:AnyObject]) {
//first set of data
let futureWeatherDictUno = futureWeatherData["list"]![0] as! [String: AnyObject]
print(futureWeatherDictUno)
let events = futureWeatherDictUno.sort({$0["dt"] < $1["dt"]})
futureDt = NSDate(timeIntervalSince1970: futureWeatherDictUno["dt"] as! NSTimeInterval)
let mainDictOne = futureWeatherDictUno["main"] as! [String: AnyObject]
futureTemp = mainDictOne["temp"] as! Double
let weatherDictOne = futureWeatherDictUno["weather"]![0] as! [String: AnyObject]
futureMainWeather = weatherDictOne["main"] as! String
futureDescription = weatherDictOne["description"] as! String
//the second set of data
let futureWeatherDictDos = futureWeatherData["list"]![1] as! [String: AnyObject]
futureDt = NSDate(timeIntervalSince1970: futureWeatherDictUno["dt"] as! NSTimeInterval)
let mainDictTwo = futureWeatherDictDos["main"] as! [String: AnyObject]
futureTemp = mainDictTwo["temp"] as! Double
let weatherDictTwo = futureWeatherDictDos["weather"]![0] as! [String: AnyObject]
futureMainWeather = weatherDictTwo["main"] as! String
futureDescription = weatherDictTwo["description"] as! String
}
}
When you go through the list array each element should already be sorted in the JSON file based on the elements dt. Also each element (futureWeatherData["list"]![0]) in the array will only have one dt key/value so you can't sort that.
What you should do is (and this is just pseudo code) is the following
let futureWeather = [Weather]()
for element : JSON in array {
let weather = Weather(json: element) //create weather element from json
futureWeather.append(weather)
}
What you don't want to do is go through each element in the list manually in your init method in the your FutureWeather class.
I would also recommend looking into using https://github.com/SwiftyJSON/SwiftyJSON and creating keys in an enum to go through the json.
As #Asdrubal pointed out in their answer SwiftyJSON is a useful library. If you want a pure-Foundation solution, you can use NSJSONSerialization to get a response from your API data. I'm posting this answer here in advance of a future, personal server-side Swift project to retrieve weather data :)
import Foundation
enum WeatherError: Int, ErrorType {
/// The API response text could not be converted to an
/// NSData object using NSUnicodeStringEncoding
case UnexpectedAPITextEncoding = 1
/// The API reponse object did not contain an array of
/// Dictionary<String, AnyObject> objects at the "list"
/// key
case UnexpectedAPIResponseFormat = 2
}
/// An abstraction of a response to the OpenWeatherMap.org forecast API.
/// Contains only date, description and temperature data, plus convenience
/// properties to display temp in F or C.
///
/// NOTE: Each of the properties on the value are Optional, reflecting the
/// fact that the API response is sparsely populated for many of its values.
struct OpenWeatherMapResponse {
/// The date of the forecast. Could be in the future
let futureDt: NSDate?
/// Textual description of the weather conditions for the forecast time
let futureDescription: String?
/// Temp provided in K
private let futureTemp: Double?
/// Temperature for the forecast time, in degrees C
var futureTempCelsius: Double? {
get {
guard let futureTemp = futureTemp else {
return nil
}
return futureTemp - 273.15
}
}
/// Temperature for the forecast time, in degrees F
var futureTempFahrenheit: Double? {
get {
guard let futureTemp = futureTemp else {
return nil
}
return (futureTemp - 273.15) * 1.8 + 32
}
}
/// Given a member of `list` from the API response,
/// creates an OpenWeatherMapResponse
init(jsonObject: AnyObject) {
if let timestamp = jsonObject["dt"] as? NSTimeInterval {
futureDt = NSDate(timeIntervalSince1970: timestamp)
} else {
futureDt = nil
}
if let mainBlock = jsonObject["main"] as? [String: AnyObject],
temp = mainBlock["temp"] as? Double {
futureTemp = temp
} else {
futureTemp = nil
}
if let weatherList = jsonObject["weather"] as? [AnyObject],
description = weatherList.first?["description"] as? String {
futureDescription = description
} else {
futureDescription = nil
}
}
/// Given a JSON Object converted from an API response, parse the object
/// into a collection of FutureWeather values.
/// - throws: WeatherError if the API response text is in an unexpected character encoding or in
/// an unexpected format
/// - returns: an array of OpenWeatherMapResponse values
static func responsesByConvertingAPIResponseString(apiResponseString: String) throws -> [OpenWeatherMapResponse] {
// NSJSONSerialization only works on NSData. Convert it before using
guard let apiData = apiResponseString.dataUsingEncoding(NSUnicodeStringEncoding) else {
throw WeatherError.UnexpectedAPITextEncoding
}
// Convert API response data to a Foundation AnyObject
let jsonObject = try NSJSONSerialization.JSONObjectWithData(apiData, options: [])
var weatherList = [OpenWeatherMapResponse]()
guard let events = jsonObject["list"] as? [[String: AnyObject]] else {
throw WeatherError.UnexpectedAPIResponseFormat
}
for event in events {
weatherList.append(OpenWeatherMapResponse(jsonObject: event))
}
return weatherList
}
}
// API response
let jsonString = "{ \"city\":{ }, \"cod\":\"200\", \"message\":0.0029, \"cnt\":40, \"list\":[ { \"dt\":1466532000, \"main\":{ \"temp\":296.52, \"temp_min\":294.864, \"temp_max\":296.52, \"pressure\":1004.95, \"sea_level\":1023.45, \"grnd_level\":1004.95, \"humidity\":58, \"temp_kf\":1.65 }, \"weather\":[ { \"id\":803, \"main\":\"Clouds\", \"description\":\"broken clouds\", \"icon\":\"04d\" } ], \"clouds\":{ }, \"wind\":{ }, \"sys\":{ }, \"dt_txt\":\"2016-06-21 18:00:00\" }, { \"dt\":1466542800, \"main\":{ }, \"weather\":[ ], \"clouds\":{ }, \"wind\":{ }, \"sys\":{ }, \"dt_txt\":\"2016-06-21 21:00:00\" }, { \"dt\":1466553600, \"main\":{ }, \"weather\":[ ], \"clouds\":{ }, \"wind\":{ }, \"sys\":{ }, \"dt_txt\":\"2016-06-22 00:00:00\" }] }"
let weatherEvents = try OpenWeatherMapResponse.responsesByConvertingAPIResponseString(jsonString)
let sortedWeatherEvents = weatherEvents.sort() { a, b in a.futureDt?.timeIntervalSince1970 < b.futureDt?.timeIntervalSince1970 }
// prints:
// event: OpenWeatherMapResponse(futureDt: Optional(2016-06-21 18:00:00 +0000), futureDescription: Optional("broken clouds"), futureTemp: Optional(296.51999999999998))
// event: OpenWeatherMapResponse(futureDt: Optional(2016-06-21 21:00:00 +0000), futureDescription: nil, futureTemp: nil)
// event: OpenWeatherMapResponse(futureDt: Optional(2016-06-22 00:00:00 +0000), futureDescription: nil, futureTemp: nil)
for event in sortedWeatherEvents {
print("event: \(event)")
}

Convert Arraylist of some Class type into JSON format using Swift

I want to hit an api using Alamofire in which I have to pass parameters as :
"reminder":
[
{
"isAlarmOn": "true",
"time": "06:29 PM"
},
{
"isAlarmOn": "true",
"time": "06:30 AM"
}
]
For achieving this, I Created an Array as
var reminderArray : [AlarmRequestModel] = [AlarmRequestModel]()
where AlarmRequestModel is Like ,
AlarmRequestModel.swift
import Foundation
class AlarmRequestModel {
var time : String = "12:00 PM"
init(time : String){
if !time.isEmpty{
self.time = time
}
}
}
and filled reminderArray as
func setArray() {
reminderArray.insert(AlarmRequestModel(time: "5:00 PM"), atIndex: 0)
reminderArray.insert(AlarmRequestModel(time: "6:00 PM"), atIndex: 1)
reminderArray.insert(AlarmRequestModel(time: "7:00 PM"), atIndex: 2)
reminderArray.insert(AlarmRequestModel(time: "8:00 PM"), atIndex: 3)
}
And while hitting the Api , I Declared the parameters as
func hitApi()
{
let parameters : [String:AnyObject] = [
"reminder" : reminderArray.description,
]
print("parmeters : \(parameters)")
}
But I didn't get the expected output ,
the output was like ->
parmeters :["reminder": [My_Swaasth.AlarmRequestModel,My_Swaasth.AlarmRequestModel,My_Swaasth.AlarmRequestModel,My_Swaasth.AlarmRequestModel]]
Please anyone Suggest , What changes Do I Need to do in order to achieve the desired output.
There is a protocoll called CustomStringConvertible which has the
var description: String property
But that won't result the desired output. So I'd rather implement a parameter value for AlarmRequestModel
extension AlarmRequestModel {
var parameterValue: Dictionary<String, String> {
return ["isAlarmOn": "true", "time": self.time]
}
}
And use this like
reminderArray.map() { reminder in return reminder.parameterValue }
here:
let parameters : [String:AnyObject] = [
"reminder" : reminderArray.map() { reminder in return reminder.parameterValue },
]
func hitApi()
{
var JSONarray: [Dictionary<String,String>] = []
for (index,_) in reminderArray.enumerate()
{
JSONarray.append(["isAlarmOn":"true","time": reminderArray[index].time])
}
let bytes = try! NSJSONSerialization.dataWithJSONObject(JSONarray, options: NSJSONWritingOptions.PrettyPrinted)
var jsonObj = try! NSJSONSerialization.JSONObjectWithData(bytes, options: .MutableLeaves) as! [Dictionary<String, String>]
print("\"reminder\":\(jsonObj)")
}
You also want to change your Alarm Request Model to this:
class AlarmRequestModel {
var time : String!
init(time : String){
if !time.isEmpty{
self.time = time
}
}
}

Resources