17

Recently i incorporated Codable in a project and to get a JSON object from a type conforming to Encodable i came up with this extension,

extension Encodable {

    /// Converting object to postable JSON
    func toJSON(_ encoder: JSONEncoder = JSONEncoder()) -> [String: Any] {
        guard let data = try? encoder.encode(self),
              let object = try? JSONSerialization.jsonObject(with: data, options: .allowFragments),
              let json = object as? [String: Any] else { return [:] }
        return json
    }
}

This works well but could there be any better way to achieve the same?

5
  • Not related but You can combine 3 separate guard condition in one comma separated !! Commented Oct 22, 2018 at 5:38
  • Why do you need this? Do you use it with alamofire? Commented Oct 22, 2018 at 5:40
  • I use it with Alamofire. In some cases it needs to add/remove a key-value from the object's JSON or replace values for some keys while sending without changing the object. Commented Oct 22, 2018 at 5:48
  • You could add a collection [String: Codable] to your object to store keys that can change. Then you will only need JSONEncoder to convert object to json data. Use that data to prepare URLRequest and send it to Alamofire's request method that takes URLRequestConvertible protocol Commented Oct 22, 2018 at 6:21
  • 3
    The name of the function is misleading. You are going to convert structs to a dictionary via JSON. Never ignore Codable and JSONSerialization errors. Make the function throw, remove the question marks after try and hand over the error to the caller. Commented Oct 22, 2018 at 6:47

2 Answers 2

29

My suggestion is to name the function toDictionary and hand over possible errors to the caller. A conditional downcast failure (type mismatch) is thrown wrapped in an typeMismatch Decoding error.

extension Encodable {

    /// Converting object to postable dictionary
    func toDictionary(_ encoder: JSONEncoder = JSONEncoder()) throws -> [String: Any] {
        let data = try encoder.encode(self)
        let object = try JSONSerialization.jsonObject(with: data)
        if let json = object as? [String: Any]  { return json }
        
        let context = DecodingError.Context(codingPath: [], debugDescription: "Deserialized object is not a dictionary")
        throw DecodingError.typeMismatch(type(of: object), context)
    }
}
Sign up to request clarification or add additional context in comments.

Comments

11

Convert encodable object to JSON string using this extension:

extension Encodable {
    /// Converting object to postable JSON
    func toJSON(_ encoder: JSONEncoder = JSONEncoder()) throws -> NSString {
        let data = try encoder.encode(self)
        let result = String(decoding: data, as: UTF8.self)
        return NSString(string: result)
    }
}

1 Comment

conversion to NSString is extra

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.