Swift 5: The given data was not valid JSON (Loading Data from API to Table View)

Viewed 2339

I'm trying to GET some data from an API. It fetches the data fine when I connect the function to an IBAction, but it doesn't work when I execute it at viewDidLoad() as a normal function.

I was hoping to generate it as the app loads up so that I can display them to a table view instead of having to click a button in order to load it every time.

I get an error of "The given data was not valid JSON" after attempting to execute the function from viewDidLoad()

Below are the codes for reference:

struct Claims: Decodable {
    let id: Int
    let submission_date: String
    let status: String
    init(json: [String:Any]) {
        id = json["id"] as? Int ?? -1
        submission_date = json["submission_date"] as? String ?? ""
        status = json["status"] as? String ?? ""
    }
}

class DashboardController: UIViewController, GIDSignInUIDelegate {

    var claimSummaryArray: [ClaimProperties] = []
    let appDelegate = UIApplication.shared.delegate as! AppDelegate

    override func viewDidLoad() {
        getData()
    }

    func getData() {
        guard let urlString = URL(string: "https://claim.ademo.work/claims/") else { return }
        var requestAPI = URLRequest(url: urlString)

        requestAPI.httpMethod = "GET"
        requestAPI.addValue("application/json", forHTTPHeaderField: "Content-Type")
        requestAPI.addValue("application/json", forHTTPHeaderField: "Accept")
        requestAPI.setValue("Bearer \(appDelegate.userAppToken)", forHTTPHeaderField: "Authorization")

        let task = URLSession.shared.dataTask(with: requestAPI) { (data, response, error) in
            if let data = data {
                do {
                    let json = try JSONDecoder().decode([Claims].self, from: data)
                    print (json)
                } catch let error {
                    print("Seems to have an error: \(error)")
                }
            }
        }
        task.resume()
    }
}

Data variable that is returned (performed via IBAction / clicking a button):

[ClaimApp.Claims(id: 1, submission_date: "2020-02-28T13:50:41.000+08:00", status: "pending"), ClaimApp.Claims(id: 2, submission_date: "2020-02-28T13:53:38.000+08:00", status: "pending"), ClaimApp.Claims(id: 3, submission_date: "2020-02-28T14:21:46.000+08:00", status: "pending"), ClaimApp.Claims(id: 4, submission_date: "2020-02-28T14:22:07.000+08:00", status: "pending")]

Error that is returned (performed via calling a normal function from viewDidLoad()):

Seems to have an error: dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.})))

P.S/ I'm new here, apologies if there are any misunderstanding or confusion.

2 Answers

Please check in the viewDidLoad whether you are getting value for userAppToken in below line that might expired, caused to be an issue

func getData() {
        guard let urlString = URL(string: "https://claim.ademo.work/claims/") else { return }
        var requestAPI = URLRequest(url: urlString)

        requestAPI.httpMethod = "GET"
        requestAPI.addValue("application/json", forHTTPHeaderField: "Content-Type")
        requestAPI.addValue("application/json", forHTTPHeaderField: "Accept")
        requestAPI.setValue("Bearer \("appDelegate.userAppToken")", forHTTPHeaderField: "Authorization")

        let task = URLSession.shared.dataTask(with: requestAPI) { (data, response, error) in
            if let data = data {
                do {
                    let str = String(decoding: data, as: UTF8.self)
                    print(str) // this is giving message HTTP Token: Access denied.
                    let json = try JSONDecoder().decode([Claims].self, from: data)
                    print (json)
                } catch let error {
                    print(error.localizedDescription)
                    print("Seems to have an error: \(error)")
                }
            }
        }
        task.resume()
    }

I think your appToken is invalid when viewDidLoad run. I see your controller is Dashboard and you get token from file so have you read it async? So you should check token have already set on appDelegate before DashboardController call viewDidLoad. Let debug or print log to see what coming first.

If token have set after DashboardController call viewDidLoad i think you need do some loading before call that controller.

Related