How to pass Encodable or Decodable as parameter in Swift 4?

Viewed 7534

I am learning JSONParsing. I followed tutorials and what I got is this:

    guard let url = URL(string: "http://localhost/test-api/public/api/register") else { return }

    var request  = URLRequest(url: url)

    request.httpMethod = "POST"

    let newUser = User.init(name: self.collectionTF[0].text, email: self.collectionTF[1].text, password: self.collectionTF[2].text)

    do {

        let jsonBody = try JSONEncoder().encode(newUser)

        request.httpBody = jsonBody

    } catch { }

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

        guard let data = data else { return }

        do {

            let json = try JSONSerialization.jsonObject(with: data) as? [String:Any]

            print(json!)

            DispatchQueue.main.async {

            if json!["status"] as! Int == 200
            {
                GeneralHelper.shared.keepLoggedIn()

                NavigationHelper.shared.moveToHome(fromVC: self)
            }

            }

        } catch { print(error.localizedDescription)}

        }.resume()

Ok, this is what I have done for register. Now, I want to create a Helper, which will do the same thing with @escaping as I we all need the parsed JSON in return.

So, I am passing the endPoint as String and then trying to pass this newUser which is a Encodable, it can be a Decodable as well in future, but it throws an error Cannot invoke 'encode' with an argument list of type '(Codable)'. Can anyone please help? And, is it better this way, by calling this function multiple times when it comes to JSONParsing?

Edit: - So, I am now using the networkRequestfunction and here is what I have done.

 let newData = User.init(name: "Rob", email: "abc@gmail.com", password: "12345678")

ApiHelper.sharedInstance.networkRequest_Post(urlString: "register", header: nil, encodingData: newData) { (response: User, urlRes, error) in
        <#code#> }

Now, it gives me this error: Cannot convert value of type '(User, _, _) -> ()' to expected argument type '(_?, HTTPURLResponse?, Error?) -> ()'. Any help?

2 Answers

I have used the same functionality in my project

Hope the below code will help

    func networkRequest_Post<T: Decodable, Q: Encodable>(urlString: String,header:[String:String]?,encodingData: Q,completion: @escaping (T?, HTTPURLResponse?, Error?) -> ()) {

    guard let url = URL(string: urlString) else { return }
    let config = URLSessionConfiguration.default
    config.timeoutIntervalForRequest = 300.0
    config.timeoutIntervalForResource = 300.0
    if header != nil{
        config.httpAdditionalHeaders = header
    }
    let session = URLSession(configuration: config)
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    do {
        let jsonBody = try JSONEncoder().encode(encodingData)
        request.httpBody = jsonBody
    } catch {}
    let task = session.dataTask(with: request) { (data,response, err) in

        if let response = response {
            print(response)
        }
        if let err = err {
            print("Failed to fetch data:", err.localizedDescription, "Error Description\(err)")
            return
        }
        guard let data = data else { return }
        do {
            print(String(data: data, encoding: String.Encoding.utf8) as Any)
            let dataReceived = try JSONDecoder().decode(T.self, from: data)
                completion(dataReceived,response as? HTTPURLResponse,err)
        } catch let jsonErr {
            print("Failed to serialize json:", jsonErr, jsonErr.localizedDescription)
            completion( nil,response as? HTTPURLResponse,jsonErr)
        }
    }
    task.resume()
}

Use -

         let newdata = User(name: "Abhi", email: "jhjhj@jhj.co", password: "123hguhj")
    networkRequest_Post(urlString: "YOUR_URL", header: nil, encodingData: newdata) { (RESPONSE_DATA:User?, URL_RESPONSE, ERROR) in
        // Do your network work here
    }

    struct User : Codable {
      var name: String?
      var email: String?
      var password: String?
    }

You can user Generics in following way...

func requestWith<T>(method: HTTPMethod, action: String,  params: Parameters?, for type: T.Type, success: @escaping (AnyObject) -> Void, failure: @escaping (AnyObject) -> Void) where T: Codable {


//do your stuff..your logic goes here..see below example

     guard let serverData = response.data else {
           return
        }

   do {
     let decoder = JSONDecoder()
     let responseData = try decoder.decode(type, from: serverData)
       success(responseData as AnyObject)
    } catch {
      print("Error = \(error.localizedDescription)")
       failure(error.localizedDescription as AnyObject)
   }

}
Related