0

I want to make a static func that could return a stuct defined like this:

struct Category: Codable {
    public let data: Array<CateItem>
    public let status: Int
    public let msg: String
}

And I have write a static func like this:

static func Get(codePoint: String, responseType: Codable){
    let urlString = UrlUtils.GetUrl(codePoint: codePoint)
    let url = URL(string: urlString)
    let task = URLSession.shared.dataTask(with: url!){
        (data,response,error) in
        if error != nil{
            print(error!)
        }else{
            if let data = data{
                JSONDecoder().decode(responseType, from: data)
            }
        }
    }
    task.resume()
}

and invoke the method like this:

HttpRequests.Get(codePoint: "getCategoryList", responseType:  Category)

but here responseType will not work.

How to fix this?

1 Answer 1

4

You want to pass type of struct, not protocol.

First, make generic constraint for your method which says that T has to conform to Decodable (since you need it just for decoding, you don’t need conforming to Encodable)

Then say that parameter should be of type T.Type - this allows compiler to infer type of T, you can avoid using this parameter, see at the end of the answer

static func Get<T: Decodable>(codePoint: String, responseType: T.Type) { ... }

... so T will be type which you'll pass to method.


Then for JSONDecoder's decode method use type of T

JSONDecoder().decode(T.self, from: data)

and then when you want to call your method, pass type of your struct like you did it within decoding

HttpRequests.Get(codePoint: "getCategoryList", responseType: Category.self)

Also note that your call is async so for returning data you'll need completion handler defined as parameter of your method

completion: @escaping (T?) -> Void

note that names of methods should start with small capital letters

static func get<T: Decodable>(codePoint: String, responseType: T.Type, completion: @escaping (T?) -> Void) {

    let urlString = UrlUtils.GetUrl(codePoint: codePoint)
    let url = URL(string: urlString)

    URLSession.shared.dataTask(with: url!) { data, response, error in

        guard let data = data else {
            print(error!)
            return completion(nil)
        }

        do {
            let decoded = try JSONDecoder().decode(T.self, from: data)
            completion(decoded)
        } catch {
            print(error)
            completion(nil)
        }
    }.resume()
}

HttpRequests.get(codePoint: "getCategoryList", responseType: Category.self) { response in
    if let category = response {
        ...
    }
}

You can also avoid using responseType parameter since type of T can be inferred from the type of parameter of completion closure

static func get<T: Codable>(codePoint: String, completion: @escaping (T?) -> Void) { ... }

HttpRequests.get(codePoint: "getCategoryList") { (category: Category?) -> Void in ... }
Sign up to request clarification or add additional context in comments.

1 Comment

By the way, the responseType parameter is not really necessary because it can be inferred from the closure type. Although there are rare situations when you want the types to be different.

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.