简体   繁体   中英

Swift: Convert object to Dictionary not working properly

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM