Swift 5: отображение данных, полученных в результате закрытия таблицы - PullRequest
0 голосов
/ 04 марта 2020

Я успешно получил некоторые данные из моего API в замыкании внутри функции. Мне нужно отобразить данные в таблице на моей раскадровке.

Я знаю причину, по которой они не отображаются, потому что данные сохраняются в закрытии, и я не могу получить к ним доступ извне, если у меня нет обработчик завершения. Я прочитал множество других вопросов здесь о переполнении стека, но я не могу понять это. Я также попытался перезагрузить таблицу, но она просто возвращает ошибку «Неожиданно найденный ноль».

Свойства заявки

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
    }
}

Таким образом, я пытаюсь отобразить данные API в моем табличном представлении.

Ответы [ 3 ]

0 голосов
/ 04 марта 2020

Это строки таблицы, которые представляют данные в tempArray, поэтому индекс должен быть indexPath.row.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ClaimCell", for: indexPath) as! AllMyClaimsTable
        cell.idField.text = String(tempArray[indexPath.row].id)
        cell.dateField.text = tempArray[indexPath.row].date
        cell.statusField.text = tempArray[indexPath.row].status
        return cell
    }

Редактировать: Кроме того, добавьте наблюдатель свойства didSet, который перезагрузит представление таблицы автоматически при изменении вашего массива. Хотя это должен быть временный обходной путь, чтобы проиллюстрировать смысл и облегчить отладку кода. Вызов tableView.reloadData() для каждой отдельной вставки или удаления очень неэффективен.

var tempArray: [ClaimProperties] = [] {
    didSet {
        print("didSet...")
        print(tempArray)
        tableView.reloadData()
    }
}

И если вы теперь добавите журнал печати внутри cellForRowAt, это должно доказать, что значения tempArray устанавливаются и сохраняются по вашему желанию. .

print("In cellForRowAt...")
print(tempArray)

Объяснение:

Причина, по которой print(tempArray) не печатает обновленные значения где-либо еще, заключается в том, что методы dataView источника tableView вызываются только один раз, когда сначала появится tableView. Они вызываются снова, только когда вы специально вызываете метод reloadData. Если вы добавите код didSet, он должен будет перезагружаться каждый раз, когда вы добавляете в ваш массив, и тогда cellForRowAt будет снова вызываться в тот момент, когда ваше закрытие завершится, что выведет обновлено (не пусто) tempArray.

Если таблица все еще не отображается после вышеуказанных исправлений, то я могу с уверенностью сказать, что проблема заключается в другом месте.

0 голосов
/ 05 марта 2020

Решение:

После поиска и внесения поправок в мой код ниже приводится рабочее решение:

Контроллер панели управления

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
    }

}

Я думаю добавление этого очень помогло abit:

DispatchQueue.main.async {
    self!.dashboardMyClaim.reloadData()
}

Отдельное спасибо всем, кто помог мне в этом вопросе. Я очень ценю это! :)

0 голосов
/ 04 марта 2020

Переместите строку reload в положение для l oop

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?.tempArray.append(ClaimProperties(id: json[n].id, date: json[n].submission_date, status: json[n].status))
            }
            self?.tableView.reloadData()

        } catch let error {
            print("Localized Error: \(error.localizedDescription)")
            print("Error: \(error)")
        }
    }
}.resume()

Вам необходимо перезагрузить компьютер после того, как l oop закончится, после того, как tempArray полностью заполнено.

...