0

My goal is to call a http service that returns a json to be parsed as an array of NewsModel objects.

I defined a struct like that

struct NewsModel: Decodable {
    var id: Int
    var title: String
    var content: String
} 

and wrote this method in Service.swift class:

func getNews(pageSize: Int, pageCount: Int, completion: @escaping ([NewsModel]?) -> ()) {

        guard let url = URL(string: "\(Service.baseURLSSMService)/news?pageSize=\(pageSize)&pageCount=\(pageCount)") else {return}

        var retVal = [NewsModel]()

        // Create URLRequest
        var request = URLRequest(url: url)
        // Set headers and http method
        request.httpMethod = "GET"
        request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
        request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")

        let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
            guard let dataResponse = data,
                error == nil else {
                    print(error?.localizedDescription ?? "Response Error")
                    completion(nil)
                    return }
            do{                
                    print("RESPONSE:\(response.debugDescription)")
                    retVal = try
                        JSONDecoder().decode([NewsModel].self, from: dataResponse)
                    completion(retVal)

            } catch let parsingError {
                print("Error", parsingError)
                completion(nil)
            }

        }
        task.resume()
    }

I need to call this method from my HomeViewController. I used this code in my viewDidLoad:

Service.sharedInstance.getNews(pageSize: 10, pageCount: 1) { (news) in

            // I need the first element of the news array   
            // I save it into a global variable 
            self.homeNews = news?.first

            DispatchQueue.main.async {
                if self.homeNews != nil {
                    self.myLabel.text = self.homeNews?.title
                }
                else {
                    self.myLabel.text = "No data received."    
                }
            }
        }

When I run the code, it always happens that the getNews function returns 0 bytes so nothing can be parsed by the JSONDecoder. This is the error message:

Error dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "No value." UserInfo={NSDebugDescription=No value.})))

If I call it twice the last time proper values are received. What am I doing wrong? Because I guess I'm doing wrong something but I cannot get it.

EDIT 1:

This is a json sample:

[
  {
    "id": 2048,
    "title": "title-sample-1",
    "content": "content-sample-1"
  },
  {
    "id": 2047,
    "title": "title-sample-2",
    "content": "content-sample-2"
  }
]

EDIT 2:

Here is the response.debugDescription

RESPONSE:Optional(<NSHTTPURLResponse: 0x2830a1160> { URL: http://.../news?pageSize=1&pageCount=1 } { Status Code: 400, Headers {
    Connection =     (
        close
    );
    Date =     (
        "Tue, 27 Nov 2018 15:38:38 GMT"
    );
    "Transfer-Encoding" =     (
        Identity
    ); } })
cicaletto79
  • 179
  • 1
  • 12
  • It looks like your JSON doesn't match with your struct. Can you add your JSON please? – Robert Dresler Nov 27 '18 at 15:13
  • Have you tested your url in a web browser? – Joakim Danielson Nov 27 '18 at 15:13
  • Also `completion(retVal)` needs to be within your do catch block – Scriptable Nov 27 '18 at 15:14
  • @RobertDresler I added a json sample in the EDIT 1 block. But I wonder why the second time the call works if the json doesn't not match my struct... – cicaletto79 Nov 27 '18 at 15:22
  • add a `completion(nil)` after `print("Error", parsingError)` and `completion(retVal)` after `retVal = try ...` and remove `DispatchQueue.main.async { completion(retVal) }` – Leo Dabus Nov 27 '18 at 15:23
  • @JoakimDanielson yes, test in a web browser is OK. – cicaletto79 Nov 27 '18 at 15:27
  • @LeoDabus I followed your suggestions. Nothing has changed though. – cicaletto79 Nov 27 '18 at 15:29
  • I know this wouldn’t fix your issue just make your code concise you need to check if your server is returning or not any data – Leo Dabus Nov 27 '18 at 15:31
  • Actually you are not using the request. Change your url to request in your dataTask call – Leo Dabus Nov 27 '18 at 15:32
  • @LeoDabus you're right, I did not use request... Now I edited my code by using it but nothing changed. – cicaletto79 Nov 27 '18 at 15:47
  • if you don't post your url nobody will be able to help you considering the fact you are stating that the data is nil. – Leo Dabus Nov 27 '18 at 15:49
  • try changing your request http header field `request.addValue("application/json", forHTTPHeaderField: "Content-Type")` https://stackoverflow.com/questions/39059317/how-can-i-fix-error-domain-nscocoaerrordomain-code-3840-no-value-userinfo-n – Leo Dabus Nov 27 '18 at 15:52
  • @LeoDabus first of all thank you for your patience :) I'm working with a local url so nobody can access the content on the internet. Via browser I always check that data is not empty. And as I wrote before if I call the service for the second time immediately it returns some data. So I guess I'm getting some error about caching or async calls... I'm getting mad about it. PS: header field changed. – cicaletto79 Nov 27 '18 at 15:58
  • @Rob I also posted the response... Error 400, bad request. If I typed some wrong code in my request I'd expect the error raising all the time. Not only the first. – cicaletto79 Nov 27 '18 at 16:00
  • Your 400 status code is telling you that your request is malformed. The content type of your GET request is _not_ JSON. It’s application/x-www-form-urlencoded. – Rob Nov 27 '18 at 16:02
  • FYI, HTTP errors, like 400, do not result in error object. You have to cast the `URLResponse` to a `HTTPURLResponse` and then look at its `statusCode`. If it’s not 2xx, then there was some server error. – Rob Nov 27 '18 at 16:15

0 Answers0