I'm trying to convert an object to NSDictionary with an extension. It works fine but if the object contains an array, then the array does not convert to NSDictionary but to Json and that is not what I want. Because I try with this Dictionary to make a request post and the body accepts [String: Any].
My code:
struct Country: Codable {
let name: String
let cities: [City]
struct City: Codable {
let name: String
}
}
extension NSDictionary {
func encode<T>(_ value: T) throws -> [String: Any]? where T: Encodable {
guard let jsonData = try? JSONEncoder().encode(value) else { return nil }
return try? JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) as? [String: Any]
}
}
Using:
let country = Country(name: "France", cities: [Country.City(name: "Paris"), Country.City(name: "Marseille")])
print(try! NSDictionary().encode(country))
Output:
["name": France, "cities": <__NSArrayI 0x600002926e60>(
{
name: "Paris",
},
{
name: "Marseille",
})
]
Expected output (what I want):
["name": France, "cities": [
[
"name": Paris,
],
[
"name": Marseille,
]
]
]
The output is correct since your result is NSDictionary
and the output is the string representation (aka description
) of NSDictionary
. <__NSArrayI 0x600002926e60> is syntactic sugar.
By the way the expected output is invalid because the city names must be in double quotes.
The extension of NSDictionary
makes no sense anyway. If you want to be able to call the method from everywhere declare a struct with a static method.
This is a swiftier version of your code. No allowFragments
and all errors are thrown
rather than being ignored.
struct DictionaryEncoder {
static func encode<T>(_ value: T) throws -> [String: Any] where T: Encodable {
let jsonData = try JSONEncoder().encode(value)
return try JSONSerialization.jsonObject(with: jsonData) as? [String: Any] ?? [:]
}
}
Copy the method and your structs into a Playground and run
let country = Country(name: "France", cities: [Country.City(name: "Paris"), Country.City(name: "Marseille")])
try! DictionaryEncoder.encode(country)
Don't print
the result, look at the result area in the Playground, the output is exactly what you want.
You need
let res = try! JSONEncoder().encode(country)
print(res.prettyPrintedJSONString!)
extension Data {
var prettyPrintedJSONString: NSString? { /// NSString gives us a nice sanitized debugDescription
guard let object = try? JSONSerialization.jsonObject(with: self, options: []),
let data = try? JSONSerialization.data(withJSONObject: object, options: [.prettyPrinted]),
let prettyPrintedString = NSString(data: data, encoding: String.Encoding.utf8.rawValue) else { return nil }
return prettyPrintedString
}
}
Result
{
"name" : "France",
"cities" : [
{
"name" : "Paris"
},
{
"name" : "Marseille"
}
]
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.