Passing Decodable Object.Type as generic parameter

whats the best/recommended way, passing Object.Type as generic parameter?

func decode<T> (model: T) {
    let myStruct = try! JSONDecoder().decode(model, from: data!)
    print(myStruct.headers.accept)
}

decode(model: Model.self)

A parameter of type T means an instance of T. If you want the client to pass in a type, use T.Type.

I tried but got this

here's the code

let data =
"""
{
    "headers":
    {
        "accept" : "*/*",
        "connection" : "close",
        "host" : "httpbin.org",
    },
    "url" : "https:httpbin.org/get"

}
""".data(using: .utf8)

struct Model: Decodable {
    var url:String
    var headers: Headers

    struct Headers: Decodable {
        var accept: String
        var connection: String
        var host: String
    }
}

func decode<T> (model: T) {
    let myStruct = try! JSONDecoder().decode(model, from: data!)
    print(myStruct)
}

decode(model: Model.self)

You need to write it like this, specifying the constraint on the T type to be Decodable:

func decode<T>(modelType: T.Type) where T : Decodable {
    let myStruct = try! JSONDecoder().decode(modelType, from: data!)
    ...
}
2 Likes

@benjaminmayo has it right — the type parameter is necessary, and needs to be correctly constrained.

One thing to note is that it's highly discouraged to try! on decoding arbitrary input: any unexpected changes (malicious/corrupted data, or any API changes) will simply crash your app, which is a bad experience for customers. You should handle the error case either by making this function throws and letting the error propagate through, or by catching the error and responding to it appropriately. [For more info on this and how things might go wrong, it might help to watch Data You Can Trust from this year's WWDC].

2 Likes

thanks @benjaminmayo its work right now,

@itaiferber yes, i used catch in actual project source i just test it on playground and i did try! for fast debugging, i assume that data is correct. , thanks for the reference. :slight_smile:

1 Like

Excellent — that's what I assumed, but it can never hurt to be safe and point it out. :slight_smile: There's a lot of try!ing out there in practice that we'd love to see people handle thoughtfully.

Hi all, here is how i pass generic Codable struct as a parameter and also return it via completion handler as parameter, allGeneric :

func getAccordingToWebServiceFlag<T:Decodable>(flagSender: WebServicesFlagSenders,codableStruct: T.Type ,completionHandler: @escaping ( _ publicDataResponseModel:T?,_ flagSender: WebServicesFlagSenders) -> Void) {

    excuteServerOperation(nil, imageData: nil, url:ServerAPIServant.webServiceFullURL(webServicesFlagSenders: flagSender), way: .get, flagSender: flagSender,completionHandler: { (result, flagSender) in
        AppDelegate().printStringBy_ispha(string: "  \(flagSender) Hmmm 🤔 \(result)")
        do {
            let jsonData = try JSONSerialization.data(withJSONObject:  result , options: .prettyPrinted)
            let decodableResponse = try! JSONDecoder().decode(codableStruct, from: jsonData)
            
            HelpingMethods.printCustomObjectBy_ispha(anyObject: decodableResponse as AnyObject)
            completionHandler(decodableResponse,flagSender)
        } catch let error {
            HelpingMethods.printStringBy_ispha(string: "😞 Codable failure with error = \(error.localizedDescription)")
             completionHandler(nil,flagSender)
        }
      
        
    }
    )
}

Kindly let me know if anything not clear or still having issues with this point.

Here is my approach, if you do want to decode arbitrary type:

// data and Model is defined here

extension Decodable {
    init(jsonData: Data) throws {
        self = try JSONDecoder().decode(Self.self, from: jsonData)
    }
}

func decode<T>(model: T.Type) {
    if let data = data,
        let decodableType = model as? Decodable.Type,
        let myStruct = try? decodableType.init(jsonData: data) {
        print(myStruct)
    }
}

decode(model: Model.self)
Terms of Service

Privacy Policy

Cookie Policy