Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios Swift 5:显示在表视图关闭中检索到的数据_Ios_Swift_Api_Networking - Fatal编程技术网

Ios Swift 5:显示在表视图关闭中检索到的数据

Ios Swift 5:显示在表视图关闭中检索到的数据,ios,swift,api,networking,Ios,Swift,Api,Networking,我已经在函数中的闭包中成功地从API获得了一些数据。我需要在我的故事板上的表格中显示数据 我知道它不显示的原因是因为数据保存在闭包中,除非我有一个完成处理程序,否则我无法从外部访问它。我在这里读了很多关于堆栈溢出的其他问题,但我不能真正理解它。我也尝试过重新加载该表,但它只返回一个错误“意外发现为零” 索赔财产 class ClaimProperties { var id: Int var date: String var status: String init

我已经在函数中的闭包中成功地从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
    }
}
仪表板控制器

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
    }
}
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
    }
    
}
struct声明:可解码{
让id:Int
提交日期:String
let状态:字符串
init(json:[字符串:任意]){
id=json[“id”]as?Int???-1
提交日期=json[“提交日期”]作为?字符串??“
status=json[“status”]作为?字符串??“
}
}
类仪表板控制器:UIViewController、GIDSignInUIDelegate{
@IBVAR表格视图:UITableView!
var tempArray:[clairproperties]=[]
重写func viewDidLoad(){
super.viewDidLoad()
tableView.delegate=self
tableView.dataSource=self
}
//一旦用户通过Google API登录,getTokenFromAPI()将以AppDelegate.swift的形式被调用
func getTokenFromAPI(usersaptoken:String){
guard let urlString=URL(字符串:https://claim.ademo.work/claims/)否则{return}
var requestAPI=URLRequest(url:urlString)
requestAPI.httpMethod=“GET”
addValue(“应用程序/json”,forHTTPHeaderField:“内容类型”)
addValue(“application/json”,用于httpheaderfield:“Accept”)
requestAPI.setValue(“承载者\(usersAppToken)”,用于HttpHeaderField:“授权”)
URLSession.shared.dataTask(带:requestAPI){
(数据、响应、错误)
如果let data=data{
做{
让json=try JSONDecoder().decode([Claims].self,from:data)

对于0中的n..将您的
重新加载
行移动到for循环下

URLSession.shared.dataTask(with:requestAPI){[weak self](数据、响应、错误)位于
如果let data=data{
做{
让json=try JSONDecoder().decode([Claims].self,from:data)

对于0..中的n,表中的行表示
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)
说明:

打印的原因(tempArray)
不会在其他任何地方打印更新后的值,因为tableView的数据源方法在tableView首次出现时只被调用一次。它们只有在您专门调用
reloadData
方法时才会再次被调用。如果您添加
didSet
代码,则每次添加到数组中时都应该重新加载,然后de>cellForRowAt
将在闭包完成执行时再次调用,这将打印更新的(非空)
tempArray

如果在上述修复之后该表仍然无法显示,那么我可以自信地说问题出在别处。

解决方案: 在搜索并修改我的代码后,以下是可行的解决方案:

仪表板控制器

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

特别感谢所有在这个问题上帮助过我的人。我真的很感激!:)

粗略检查(在cellForRow实现中),也许应该是indexPath.row而不是indexPath.section。现在
section
为0,所以如果
tempArray
有一些值,则实现类似
tempArray[indexPath.section]
必须在第一(0)个索引中返回值。但是OP说,
意外地发现出现了nil
错误。我同意您@emrcftci的观点,但为了正确显示数据,
cellForRow
中的实现也应该被更正。@Wattholm是的,您是对的,应该使用
tempArray[indexPath.row]完成
而不是
tempArray[indexPath.section]
self?.tableView.reloadData()给出了一个错误:“无法对'DashboardController'类型的非可选值使用可选链接”,因此我删除了问号。之后,我得到了一个错误“隐式展开可选值时意外发现为零”,请添加
[弱自我]
之前(数据、响应、错误)
,请重新检查我的答案:)你能告诉我你面对的是哪一行错误吗?@ShaniceC.Oops!对不起,错过了那一部分。我试过了,仍然显示相同的错误。这里的屏幕截图供你参考:我想你的
tableView
nil
请检查你的
tableView
的插座连接。你能告诉我哪个专业perty是
nil
self
tableView
在这种情况下可以是
nil
。您可以在控制台左侧轻松找到这一点。我已将其更改为row,运行时没有任何错误,但也没有显示任何内容。我猜这是因为我在getTokenFromAPI()中附加了tempArray未在函数外“保存”。因此它仍然为空。但感谢您在下标上指出!除了此修复之外,请按照@emrcftci在其回答中的建议执行,因为当数据更改时,应重新加载tableView。这在闭包中发生。此外,您的
tempArray
Da的属性shboardViewControlle