Converting Firebase Datasnapshot to codable JSON data - json

I'm using Firebase Database and I'm attempting to retrieve and use data with NSObject. I'm receiving an NSUnknownKeyException error when running the app, causing it to crash.
NSObject:
class WatchList: NSObject {
var filmid: Int?
}
Firebase Code:
ref.child("users").child(uid!).child("watchlist").observe(DataEventType.childAdded, with: { (info) in
print(info)
if let dict = info.value as? [String: AnyObject] {
let list = WatchList()
list.setValuesForKeys(dict)
print(list)
}
}, withCancel: nil)
I'm not sure of what could cause this.
Also, to enhance this solution is their a way to take this data and, instead of using NSObject, use Codable and JSONDecoder with the Firebase data?

You can simply use JSONSerialization to convert the snapshot value property from Any to Data:
let data = try? JSONSerialization.data(withJSONObject: snapshot.value)
You can also extend Firebase DataSnapshot type and add a data and json string properties to it:
import Firebase
extension DataSnapshot {
var data: Data? {
guard let value = value, !(value is NSNull) else { return nil }
return try? JSONSerialization.data(withJSONObject: value)
}
var json: String? { data?.string }
}
extension Data {
var string: String? { String(data: self, encoding: .utf8) }
}
usage:
guard let data = snapshot.data else { return }

It's 2021 now.
Firebase finally added support for decoding Firestore documents. Just let your objects conform to Codable and decode like this:
let result = Result {
try document?.data(as: City.self)
}
switch result {
case .success(let city):
if let city = city {
print("City: \(city)")
} else {
print("Document does not exist")
}
case .failure(let error):
// A `City` value could not be initialized from the DocumentSnapshot.
print("Error decoding city: \(error)")
}
Just don't forget to add the 'FirebaseFirestoreSwift' pod and then import it into your file.
Read more:
https://firebase.google.com/docs/firestore/query-data/get-data#custom_objects
Original answer
A really nice library to use here is Codable Firebase which I am also using in my project. Just make your class / struct conform to Codable protocol and use FirebaseDecoder to decode your Firebase data into a Swift object.
Example:
Database.database().reference().child("model").observeSingleEvent(of: .value, with: { snapshot in
guard let value = snapshot.value else { return }
do {
let model = try FirebaseDecoder().decode(Model.self, from: value)
print(model)
} catch let error {
print(error)
}
})

Related

Cannot convert value of type 'User' to expected argument type '[String : Any]' [duplicate]

I am trying to decode data from a Firebase DataSnapshot so that it can be decoded using JSONDecoder.
I can decode this data fine when I use a URL to access it with a network request (obtaining a Data object).
However, I want to use the Firebase API to directly obtain the data, using observeSingleEvent as described on this page.
But, when I do this, I cannot seem to convert the result into a Data object, which I need to use JSONDecoder.
Is it possible to do the new style of JSON decoding with a DataSnapshot? How is it possible? I can't seem to figure it out.
I have created a library called CodableFirebase that provides Encoders and Decoders that are designed specifically for Firebase.
So for the example above:
import Firebase
import CodableFirebase
let item: GroceryItem = // here you will create an instance of GroceryItem
let data = try! FirebaseEncoder().encode(item)
Database.database().reference().child("pathToGraceryItem").setValue(data)
And here's how you will read the same data:
Database.database().reference().child("pathToGraceryItem").observeSingleEvent(of: .value, with: { (snapshot) in
guard let value = snapshot.value else { return }
do {
let item = try FirebaseDecoder().decode(GroceryItem.self, from: value)
print(item)
} catch let error {
print(error)
}
})
I've converted Firebase Snapshots using JSONDecoder by converting snapshots back to JSON in Data format. Your struct needs to conform to Decodable or Codable. I've done this with SwiftyJSON but this example is using JSONSerialization and it still works.
JSONSnapshotPotatoes {
"name": "Potatoes",
"price": 5,
}
JSONSnapshotChicken {
"name": "Chicken",
"price": 10,
"onSale": true
}
struct GroceryItem: Decodable {
var name: String
var price: Double
var onSale: Bool? //Use optionals for keys that may or may not exist
}
Database.database().reference().child("grocery_item").observeSingleEvent(of: .value, with: { (snapshot) in
guard let value = snapshot.value as? [String: Any] else { return }
do {
let jsonData = try JSONSerialization.data(withJSONObject: value, options: [])
let groceryItem = try JSONDecoder().decode(GroceryItem.self, from: jsonData)
print(groceryItem)
} catch let error {
print(error)
}
})
Please note that if your JSON keys are not the same as your Decodable struct. You'll need to use CodingKeys. Example:
JSONSnapshotSpinach {
"title": "Spinach",
"price": 10,
"onSale": true
}
struct GroceryItem: Decodable {
var name: String
var price: Double
var onSale: Bool?
enum CodingKeys: String, CodingKey {
case name = "title"
case price
case onSale
}
}
You can find more information on this using Apple Docs here.
No. Firebase returns a FIRDataSnapshot that can't be decodable. You can use this structure however, which is pretty simple and easy to understand:
struct GroceryItem {
let key: String
let name: String
let addedByUser: String
let ref: FIRDatabaseReference?
var completed: Bool
init(name: String, addedByUser: String, completed: Bool, key: String = "") {
self.key = key
self.name = name
self.addedByUser = addedByUser
self.completed = completed
self.ref = nil
}
init(snapshot: FIRDataSnapshot) {
key = snapshot.key
let snapshotValue = snapshot.value as! [String: AnyObject]
name = snapshotValue["name"] as! String
addedByUser = snapshotValue["addedByUser"] as! String
completed = snapshotValue["completed"] as! Bool
ref = snapshot.ref
}
func toAnyObject() -> Any {
return [
"name": name,
"addedByUser": addedByUser,
"completed": completed
]
}
}
And use toAnyObject() to save your item:
let groceryItemRef = ref.child("items")
groceryItemRef.setValue(groceryItem.toAnyObject())
Source: https://www.raywenderlich.com/139322/firebase-tutorial-getting-started-2
Or you can use this solution for children
extension DatabaseReference {
func makeSimpleRequest<U: Decodable>(completion: #escaping (U) -> Void) {
self.observeSingleEvent(of: .value, with: { snapshot in
guard let object = snapshot.children.allObjects as? [DataSnapshot] else { return }
let dict = object.compactMap { $0.value as? [String: Any] }
do {
let jsonData = try JSONSerialization.data(withJSONObject: dict, options: [])
let parsedObjects = try JSONDecoder().decode(U.self, from: jsonData)
completion(parsedObjects)
} catch let error {
print(error)
}
})
}
}
and use
self.refPriceStatistics.child(productId).makeSimpleRequest { (parsedArray: [YourArray]) in
callback(parsedArray)
}
If your data type is Codable you can use the following solution to decode directly. You do not need any plugin. I used the solution for Cloud Firestore.
import Firebase
import FirebaseFirestoreSwift
let db = Firestore.firestore()
let query = db.collection("CollectionName")
.whereField("id", isEqualTo: "123")
guard let documents = snapshot?.documents, error == nil else {
return
}
if let document = documents.first {
do {
let decodedData = try document.data(as: ModelClass.self)
// ModelClass a Codable Class
}
catch let error {
//
}
}
You can convert the value returned by Firebase to Data, and then decode that.
Add this extension to your project:
extension Collection {
//Designed for use with Dictionary and Array types
var jsonData: Data? {
return try? JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
}
}
Then use it to convert the value of the observed snapshot into data, which can then be decoded:
yourRef.observe(.value) { (snapshot) in
guard snapshot.exists(),
let value = snapshot.value as? [String],
let data = value.jsonData else {
return
}
//cast to expected type
do {
let yourNewObject = try JSONDecoder().decode([YourClass].self, from: data)
} catch let decodeError {
print("decodable error")
}
}
You can use this library CodableFirebase or the following extension can be helpful.
extension JSONDecoder {
func decode<T>(_ type: T.Type, from value: Any) throws -> T where T : Decodable {
do {
let data = try JSONSerialization.data(withJSONObject: value, options: .prettyPrinted)
let decoded = try decode(type, from: data)
return decoded
} catch {
throw error
}
}

Swift: How to use response from SocketIO emitWithAck method

I'm using the SocketIO library to connect my iOS app to my server.
I want to emit some data to the server and get a json dictionary back in the acknowledgment. I currently have something like this:
SocketHandler.mySocket.emitWithAck("my_event", [session, someInput]).timingOut(after: 3) {data in
let myData = try? JSONDecoder().decode(myStruct.self, from: data)
MyStruct is defined as Class inheriting from Decodable and resembles the structure of the json I expect.
I get the following error: Cannot convert value of type 'Any' to expected argument type 'Data'
Any idea how I can tackle that type casting? Or would I need to go a totally other route?
(Swift 4.1 for iOS 11.3)
Cheers!
If anyone else is wondering how to use SocketIO with Decodable, I created a little extension for the client to accept Decodable in the callback, based on Dan Karbayev's answer.
import Foundation
import SocketIO
extension Decodable {
init(from any: Any) throws {
let data = try JSONSerialization.data(withJSONObject: any)
self = try JSONDecoder().decode(Self.self, from: data)
}
}
extension SocketIOClient {
func on<T: Decodable>(_ event: String, callback: #escaping (T)-> Void) {
self.on(event) { (data, _) in
guard !data.isEmpty else {
print("[SocketIO] \(event) data empty")
return
}
guard let decoded = try? T(from: data[0]) else {
print("[SocketIO] \(event) data \(data) cannot be decoded to \(T.self)")
return
}
callback(decoded)
}
}
}
Usage:
socket.on("location") { (data: LocationEventData) in
// ...
}
socket.on("success") { (name: String) in
// ...
}
Where LocationEventData and String are Decodable.
There're two things:
decode(_:from:) accepts a Data as a second parameter. To be able to decode from Any you'll need to add an extension to first serialize the data and then pass it to JSONDecoder, like this:
extension Decodable {
init(from any: Any) throws {
let data = try JSONSerialization.data(withJSONObject: any)
self = try JSONDecoder().decode(Self.self, from: data)
}
}
AckCallback's parameter is of an array type (i.e. [Any]), so you should get the first element of that array.
To make sure that you have indeed a decodable data (a dictionary or a JSON object) you can write something like this:
SocketHandler.mySocket.emitWithAck("my_event", [session, someInput]).timingOut(after: 3) { data in
guard let dict = data.first as? [String: Any] else { return }
let myData = try? myStruct(from: dict)
// ...
}

swift - convert json type Int to String

I have json data like this code below:
{
"all": [
{
"ModelId": 1,
"name": "ghe",
"width": 2
},
{
"ModelId": 2,
"name": "ban",
"width": 3
}]
}
I try to get the modelId and convert it to String but it's not working with my code:
let data = NSData(contentsOf: URL(string: url)!)
do {
if let data = data, let json = try JSONSerialization.jsonObject(with: data as Data) as? [String: Any], let models = json["all"] as? [[String:Any]] {
for model in models {
if let name = model["ModelId"] as? String {
_modelList.append(name)
}
}
}
completion(_modelList)
}catch {
print("error")
completion(nil)
}
How to fix this issue? Thanks.
I think ModelId is integer type. So, can you try to cast it to Integer
for model in models {
if let name = model["ModelId"] as? Int{
_modelList.append("\(name)")
}
}
Hope, it will help you.
if let as? is to unwrap, not type casting. So you unwrap first, then you cast it into string.
for model in models {
if let name = model["ModelId"] as? Int {
_modelList.append("\(name)")
}
}
Currently you are looking for a wrong key ,
for model in models {
if let name = model["ModelId"] as? NSNumber {
_modelList.append(name.stringValue)
}
}
As long as you are using JSONSerialization.jsonObject to parse your JSON you have very little control over the type the deserialiser will create, you basically let the parser decide. Sensible as it is it will create "some kind of " NSNumber of an Int type from a number without quotes. This can not be cast to a String, therefore your program will fail.
You can do different things in order to "fix" this problem, I would like to suggest the Codable protocol for JSON-parsing, but this specific problem can probably only be solved using a custom initialiser which looks kind of verbose as can be seen in this question.
If you just want to convert your NSNumber ModelId to a String you will have to create a new object (instead of trying to cast in vain). In your context this might simply be
if let name = String(model["ModelId"]) { ...
This is still not an elegant solution, however it will solve the problem at hand.
another approach is:
import Foundation
struct IntString: Codable
{
var value: String = "0"
init(from decoder: Decoder) throws
{
// get this instance json value
let container = try decoder.singleValueContainer()
do
{
// try to parse the value as int
value = try String(container.decode(Int.self))
}
catch
{
// if we failed parsing the value as int, try to parse it as a string
value = try container.decode(String.self)
}
}
func encode(to encoder: Encoder) throws
{
var container = encoder.singleValueContainer()
try container.encode(value)
}
}
my solution is to create a new struct that will be able to receive either a String or and Int and parse it as a string, this way in my code i can decide how to treat it, and when my server sends me sometimes an Int value and sometimes a json with that same key as a String value - the parser can parse it without failing
of course you can do it with any type (date / double / float / or even a full struct), and even insert it with some logic of your own (say get the string value of an enum based on the received value and use it as index or whatever)
so your code should look like this:
import Foundation
struct Models: Codable {
let all: [All]
}
struct All: Codable {
let modelID: IntString
let name: String
let width: IntString
enum CodingKeys: String, CodingKey {
case modelID = "ModelId"
case name = "name"
case width = "width"
}
}
parse json into the Models struct:
let receivedModel: Decodable = Bundle.main.decode(Models.self, from: jsonData!)
assuming you'r json decoder is:
import Foundation
extension Bundle
{
func decode<T: Decodable>(_ type: T.Type, from jsonData: Data, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) -> T
{
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = dateDecodingStrategy
decoder.keyDecodingStrategy = keyDecodingStrategy
do
{
return try decoder.decode(T.self, from: jsonData)
}
catch DecodingError.keyNotFound(let key, let context)
{
fatalError("Failed to decode \(jsonData) from bundle due to missing key '\(key.stringValue)' not found – \(context.debugDescription)")
}
catch DecodingError.typeMismatch(let type, let context)
{
print("Failed to parse type: \(type) due to type mismatch – \(context.debugDescription) the received JSON: \(String(decoding: jsonData, as: UTF8.self))")
fatalError("Failed to decode \(jsonData) from bundle due to type mismatch – \(context.debugDescription)")
}
catch DecodingError.valueNotFound(let type, let context)
{
fatalError("Failed to decode \(jsonData) from bundle due to missing \(type) value – \(context.debugDescription)")
}
catch DecodingError.dataCorrupted(_)
{
fatalError("Failed to decode \(jsonData) from bundle because it appears to be invalid JSON")
}
catch
{
fatalError("Failed to decode \(jsonData) from bundle: \(error.localizedDescription)")
}
}
}

Can Swift 4's JSONDecoder be used with Firebase Realtime Database?

I am trying to decode data from a Firebase DataSnapshot so that it can be decoded using JSONDecoder.
I can decode this data fine when I use a URL to access it with a network request (obtaining a Data object).
However, I want to use the Firebase API to directly obtain the data, using observeSingleEvent as described on this page.
But, when I do this, I cannot seem to convert the result into a Data object, which I need to use JSONDecoder.
Is it possible to do the new style of JSON decoding with a DataSnapshot? How is it possible? I can't seem to figure it out.
I have created a library called CodableFirebase that provides Encoders and Decoders that are designed specifically for Firebase.
So for the example above:
import Firebase
import CodableFirebase
let item: GroceryItem = // here you will create an instance of GroceryItem
let data = try! FirebaseEncoder().encode(item)
Database.database().reference().child("pathToGraceryItem").setValue(data)
And here's how you will read the same data:
Database.database().reference().child("pathToGraceryItem").observeSingleEvent(of: .value, with: { (snapshot) in
guard let value = snapshot.value else { return }
do {
let item = try FirebaseDecoder().decode(GroceryItem.self, from: value)
print(item)
} catch let error {
print(error)
}
})
I've converted Firebase Snapshots using JSONDecoder by converting snapshots back to JSON in Data format. Your struct needs to conform to Decodable or Codable. I've done this with SwiftyJSON but this example is using JSONSerialization and it still works.
JSONSnapshotPotatoes {
"name": "Potatoes",
"price": 5,
}
JSONSnapshotChicken {
"name": "Chicken",
"price": 10,
"onSale": true
}
struct GroceryItem: Decodable {
var name: String
var price: Double
var onSale: Bool? //Use optionals for keys that may or may not exist
}
Database.database().reference().child("grocery_item").observeSingleEvent(of: .value, with: { (snapshot) in
guard let value = snapshot.value as? [String: Any] else { return }
do {
let jsonData = try JSONSerialization.data(withJSONObject: value, options: [])
let groceryItem = try JSONDecoder().decode(GroceryItem.self, from: jsonData)
print(groceryItem)
} catch let error {
print(error)
}
})
Please note that if your JSON keys are not the same as your Decodable struct. You'll need to use CodingKeys. Example:
JSONSnapshotSpinach {
"title": "Spinach",
"price": 10,
"onSale": true
}
struct GroceryItem: Decodable {
var name: String
var price: Double
var onSale: Bool?
enum CodingKeys: String, CodingKey {
case name = "title"
case price
case onSale
}
}
You can find more information on this using Apple Docs here.
No. Firebase returns a FIRDataSnapshot that can't be decodable. You can use this structure however, which is pretty simple and easy to understand:
struct GroceryItem {
let key: String
let name: String
let addedByUser: String
let ref: FIRDatabaseReference?
var completed: Bool
init(name: String, addedByUser: String, completed: Bool, key: String = "") {
self.key = key
self.name = name
self.addedByUser = addedByUser
self.completed = completed
self.ref = nil
}
init(snapshot: FIRDataSnapshot) {
key = snapshot.key
let snapshotValue = snapshot.value as! [String: AnyObject]
name = snapshotValue["name"] as! String
addedByUser = snapshotValue["addedByUser"] as! String
completed = snapshotValue["completed"] as! Bool
ref = snapshot.ref
}
func toAnyObject() -> Any {
return [
"name": name,
"addedByUser": addedByUser,
"completed": completed
]
}
}
And use toAnyObject() to save your item:
let groceryItemRef = ref.child("items")
groceryItemRef.setValue(groceryItem.toAnyObject())
Source: https://www.raywenderlich.com/139322/firebase-tutorial-getting-started-2
Or you can use this solution for children
extension DatabaseReference {
func makeSimpleRequest<U: Decodable>(completion: #escaping (U) -> Void) {
self.observeSingleEvent(of: .value, with: { snapshot in
guard let object = snapshot.children.allObjects as? [DataSnapshot] else { return }
let dict = object.compactMap { $0.value as? [String: Any] }
do {
let jsonData = try JSONSerialization.data(withJSONObject: dict, options: [])
let parsedObjects = try JSONDecoder().decode(U.self, from: jsonData)
completion(parsedObjects)
} catch let error {
print(error)
}
})
}
}
and use
self.refPriceStatistics.child(productId).makeSimpleRequest { (parsedArray: [YourArray]) in
callback(parsedArray)
}
If your data type is Codable you can use the following solution to decode directly. You do not need any plugin. I used the solution for Cloud Firestore.
import Firebase
import FirebaseFirestoreSwift
let db = Firestore.firestore()
let query = db.collection("CollectionName")
.whereField("id", isEqualTo: "123")
guard let documents = snapshot?.documents, error == nil else {
return
}
if let document = documents.first {
do {
let decodedData = try document.data(as: ModelClass.self)
// ModelClass a Codable Class
}
catch let error {
//
}
}
You can convert the value returned by Firebase to Data, and then decode that.
Add this extension to your project:
extension Collection {
//Designed for use with Dictionary and Array types
var jsonData: Data? {
return try? JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
}
}
Then use it to convert the value of the observed snapshot into data, which can then be decoded:
yourRef.observe(.value) { (snapshot) in
guard snapshot.exists(),
let value = snapshot.value as? [String],
let data = value.jsonData else {
return
}
//cast to expected type
do {
let yourNewObject = try JSONDecoder().decode([YourClass].self, from: data)
} catch let decodeError {
print("decodable error")
}
}
You can use this library CodableFirebase or the following extension can be helpful.
extension JSONDecoder {
func decode<T>(_ type: T.Type, from value: Any) throws -> T where T : Decodable {
do {
let data = try JSONSerialization.data(withJSONObject: value, options: .prettyPrinted)
let decoded = try decode(type, from: data)
return decoded
} catch {
throw error
}
}

How to convert a Swift object to a dictionary

I'm relatively new to iOS programming. However, I would have assumed that Swift would have an automated way of converting objects to JSON and vice versa. That being said, I have found several libraries that can do this.
HOWEVER...
It seems that no matter how you post data to a web service (even using something like AlamoFire), the requests must be a dictionary. All these forums show examples of how easy it is to convert the returned JSON string to objects. True. But the request needs to be manually coded. That is, go through all of the object properties and map them as a dictionary.
So my question is this: Am I missing something? Have I got this all wrong and there's a super-easy way to either (a) send JSON (instead of a dictionary) in the REQUEST or (b) convert an object automatically to a dictionary?
Again, I see how easy it is to deal with a JSON response. I'm just looking for an automatic way to convert the request object I want to post to a web service into a format that a library like AlamoFire (or whatever) requires. With other languages this is fairly trivial, so I'm hoping there's an equally easy and automated way with Swift.
I must disagree with #Darko.
In Swift 2,
use protocol oriented programming and the simple reflection offered by Mirror class :
protocol JSONAble {}
extension JSONAble {
func toDict() -> [String:Any] {
var dict = [String:Any]()
let otherSelf = Mirror(reflecting: self)
for child in otherSelf.children {
if let key = child.label {
dict[key] = child.value
}
}
return dict
}
}
then you can use this protocol with your request class and produce the desired dictionary :
class JsonRequest : JSONAble {
var param1 : String?
// ...
}
let request = JsonRequest()
// set params of the request
let dict = request.toDict()
// use your dict
My solution to this will be something like this:
extension Encodable {
var dict : [String: Any]? {
guard let data = try? JSONEncoder().encode(self) else { return nil }
guard let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String:Any] else { return nil }
return json
}
}
and usage will be something like this:
movies.compactMap { $0.dict }
Swift currently does not support advanced reflection like Java or C# so the answer is: no, there is not an equally easy and automated way with pure Swift.
[Update] Swift 4 has meanwhile the Codable protocol which allows serializing to/from JSON and PLIST.
typealias Codable = Decodable & Encodable
Without using reflection, and works for nested objects (Swift 4):
protocol Serializable {
var properties:Array<String> { get }
func valueForKey(key: String) -> Any?
func toDictionary() -> [String:Any]
}
extension Serializable {
func toDictionary() -> [String:Any] {
var dict:[String:Any] = [:]
for prop in self.properties {
if let val = self.valueForKey(key: prop) as? String {
dict[prop] = val
} else if let val = self.valueForKey(key: prop) as? Int {
dict[prop] = val
} else if let val = self.valueForKey(key: prop) as? Double {
dict[prop] = val
} else if let val = self.valueForKey(key: prop) as? Array<String> {
dict[prop] = val
} else if let val = self.valueForKey(key: prop) as? Serializable {
dict[prop] = val.toDictionary()
} else if let val = self.valueForKey(key: prop) as? Array<Serializable> {
var arr = Array<[String:Any]>()
for item in (val as Array<Serializable>) {
arr.append(item.toDictionary())
}
dict[prop] = arr
}
}
return dict
}
}
Just implement properties and valueForKey for the custom objects you want to convert. For example:
class Question {
let title:String
let answer:Int
init(title:String, answer:Int) {
self.title = title
self.answer = answer
}
}
extension Question : Serializable {
var properties: Array<String> {
return ["title", "answer"]
}
func valueForKey(key: String) -> Any? {
switch key {
case "title":
return title
case "answer":
return answer
default:
return nil
}
}
}
You can add more value types in the toDictionary function if you need.
The latest solution that I found after lots of digging throughout Stack Overflow is:
//This block of code used to convert object models to json string
let jsonData = try JSONEncoder().encode(requestData)
let jsonString = String(data: jsonData, encoding: .utf8)!
print(jsonString)
//This method is used to convert jsonstring to dictionary [String:Any]
func jsonToDictionary(from text: String) -> [String: Any]? {
guard let data = text.data(using: .utf8) else { return nil }
let anyResult = try? JSONSerialization.jsonObject(with: data, options: [])
return anyResult as? [String: Any]
}
//Use above method something like this
let params = jsonToDictionary(from: jsonString) ?? [String : Any]()
//Use params to pass in paramters
Alamofire.request(completeUrl, method: .post, parameters: params, encoding:JSONEncoding.prettyPrinted, headers: myHeaders){
response in
//Do whatever you want with response of it.
}
Note:
I combine this solution from multiple answers.
This solution i used with alamofire because alamofire only accept parameter at this format "[String:Any]".
You can also use the ObjectMapper library. It has a "toJSON" method that converts your object to a dictionary.
in short
let dict = Mirror(reflecting: self).children.map({ $0 }).reduce(into: [:]) { $0[$1.label] = $1.value }
Example how to use Mirror with conversion to specific Dictionary type:
protocol DictionaryConvertible { }
extension DictionaryConvertible {
func toDictionary() -> [String: CustomStringConvertible] {
Dictionary(
uniqueKeysWithValues: Mirror(reflecting: self).children
.compactMap { child in
if let label = child.label,
let value = child.value as? CustomStringConvertible {
return (label, value)
} else {
return nil
}
}
)
}
}