I've successfully obtained some data from my API in a closure within a function. I need to display the data to the table on my storyboard.
I know the reason why it's not displaying is because the data is saved within the closure and I can't access it from the outside unless I have a completion handler. I've read a bunch of other questions here on Stack Overflow but I can't really understand it. I've tried reloading the table as well, but it just returns an error of:
'Unexpectedly found nil'.
Claim Properties
class ClaimProperties {
var id: Int
var date: String
var status: String
init(id: Int, date: String, status: String) {
self.id = id
self.date = date
self.status = status
}
}
DashboardController
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 {
@IBOutlet weak var tableView: UITableView!
var tempArray: [ClaimProperties] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
// getTokenFromAPI() gets called form AppDelegate.swift once the user logs in via Google API
func getTokenFromAPI(usersAppToken:String) {
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 \(usersAppToken)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: requestAPI) {
(data, response, error) in
if let data = data {
do {
let json = try JSONDecoder().decode([Claims].self, from: data)
for n in 0..<json.count {
self.tempArray.append(ClaimProperties(id: json[n].id, date: json[n].submission_date, status: json[n].status))
}
// This is the data I'm trying to display -> tempArray
} catch let error {
print("Localized Error: \(error.localizedDescription)")
print("Error: \(error)")
}
}
}.resume()
}
}
extension DashboardController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tempArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ClaimCell", for: indexPath) as! AllMyClaimsTable
cell.idField.text = String(tempArray[indexPath.section].id)
cell.dateField.text = tempArray[indexPath.section].date
cell.statusField.text = tempArray[indexPath.section].status
return cell
}
}
In summary, what I'm trying to do is just to display API data to my table view.
After searching around and amending my code, below is the working solution:
Dashboard Controller
import UIKit
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 {
@IBOutlet weak var dashboardMyClaim: UITableView!
var myClaimArray: [PropertyExistingClaim] = []
var idToken = ""
var email = ""
var appToken = ""
override func viewDidLoad() {
super.viewDidLoad()
idToken = AppDelegate.originalAppDelegate.userIdToken
email = AppDelegate.originalAppDelegate.userEmail
tableSettings()
getAppToken()
}
func tableSettings() {
dashboardMyClaim.delegate = self
dashboardMyClaim.dataSource = self
}
// Get user's App Token from Google API
func getAppToken() {
guard let urlString = URL(string: "https://claim.ademo.work/sessions/") else { return }
var requestAPI = URLRequest(url: urlString)
let parameters: [String: Any] = ["email":email, "platform":"web", "id_token":idToken]
requestAPI.httpMethod = "POST"
requestAPI.setValue("Application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else {return}
requestAPI.httpBody = httpBody
requestAPI.timeoutInterval = 20
URLSession.shared.dataTask(with: requestAPI) { (data, response, error) in
if let data = data {
do {
let jsonResult = try JSONDecoder().decode(SignIn.self, from: data)
self.getClaimFromAPI(usersAppToken: jsonResult.app_token)
} catch {
print(error)
}
}
}.resume()
}
// Use the App Token to GET claims from the database / API
func getClaimFromAPI(usersAppToken:String) {
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 \(usersAppToken)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: requestAPI) { [weak self] (data, response, error) in
if let data = data {
do {
let json = try JSONDecoder().decode([Claims].self, from: data)
for n in 0..<json.count {
self!.myClaimArray.append(PropertyExistingClaim(id: json[n].id, date: json[n].submission_date, desc: "-", amount: "-", amountMyr: "-", currency: "-", status: json[n].status))
}
DispatchQueue.main.async {
self!.dashboardMyClaim.reloadData()
}
} catch let error {
print("Localized Error: \(error.localizedDescription)")
print("Error: \(error)")
}
}
}.resume()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToNewClaimDashboard" {
let destinationVC = segue.destination as? NewClaimDashboardController
}
}
}
extension DashboardController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
myClaimArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = dashboardMyClaim.dequeueReusableCell(withIdentifier: "DashboardMyClaim", for: indexPath) as! TableDashboardMyClaim
cell.dateField.text = "Date: \(myClaimArray[indexPath.row].date)"
cell.descriptionField.text = "Description: \(myClaimArray[indexPath.row].desc)"
cell.amountMyrField.text = "RM \(myClaimArray[indexPath.row].amountMyr)"
cell.idField.text = "#\(myClaimArray[indexPath.row].id)"
cell.statusField.text = "\(myClaimArray[indexPath.row].status)"
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 120.0
}
}
I think adding this has helped quite abit:
DispatchQueue.main.async {
self!.dashboardMyClaim.reloadData()
}
Special thanks to all those that has helped me on this question. I really appreciate it! :)