从[String]到标签的文本。第一次无法使用文本

时间:2019-12-26 12:45:28

标签: swift

快速开展学校项目(自己学习这种语言),我需要使用一些Headerfields发出 Get方法HTTP请求,并将其放入json对象(这部分工作良好)。

>

此后,我想显示JsonObjects从新到旧的最后5个部分,因此我决定将它们放在Strings表中,并能够将这些Strings(按我的需要)分配给几个UILabel。文本。

当我第一次按下按钮(分配给@IBAction)时,标签保持不变,但表已满(在} catch {之前使用print(self.tableau)进行了尝试) )

变量初始化:

var tableau: [String] = []

struct Donnee: Decodable                            
    {
      let device_id: String
      let raw: String
      let receivedString: String
      let time: String


        init(json : [String: Any]){
            device_id       = json["device_id"] as? String ?? ""
            raw             = json["raw"] as? String ?? ""
            receivedString  = json["receivedString"] as? String ?? ""
            time            = json["time"] as? String ?? ""

        }
    }

代码制作问题:

@IBAction func sendButtonTapped(_ sender: AnyObject) {
        // Send HTTP GET Request

              // Define server side script URL
              let scriptUrl = "https://lora-thomas-slave.data.thethingsnetwork.org/api/v2/query?last=7d"

              // Create NSURL Ibject
              let myUrl = NSURL(string: scriptUrl);

              // Creaste URL Request
               let request = NSMutableURLRequest(url:myUrl! as URL);

              // Set request HTTP method to GET. It could be POST as well
               request.httpMethod = "GET"

              // Or it could be a single Authorization Token value
               request.addValue("application/json", forHTTPHeaderField: "Accept")
               request.addValue("key ttn-account-v2.*************", forHTTPHeaderField: "Authorization")

              // Excute HTTP Request
               URLSession.shared.dataTask(with: request as URLRequest) {(data, response, error) in
                   do{
                       // Try to assign Json Lora data into an array of Structured data
                       let donne = try JSONDecoder().decode([Donnee].self, from: data!)

                       // For each data, print the received string
                       let compt: Int = donne.count         //compt = number of json objects
                       var j : Int = 0
                       var chaine: String = " "
                       var x : Int = 0
                       for i in donne{
                           if (j > (compt-6)){
                               chaine = i.time.split(separator: "T")[0]  + " " + i.time.split(separator: "T")[1].split(separator: ".")[0] + " : " + i.receivedString
                               self.tableau.append(chaine)
                               x += 1
                           }
                           j += 1
                       }
                   }catch{
                       print("error !")
                   }
               }.resume()


                    //This code is executing the second time that i pushed the button
                    //**********************//
                    if(self.tableau.count != 0){
                        self.labelMess0.text = self.tableau[4]
                        self.labelMess1.text = self.tableau[3]
                        self.labelMess2.text = self.tableau[2]
                        self.labelMess3.text = self.tableau[1]
                        self.labelMess4.text = self.tableau[0]
                    }
                  //**********************//
        }

我已经尝试在捕获之前将代码放在// ******** //之间,但是我收到一个错误消息,告诉我只有主线程才能修改UILabel.text ^^(UILabel.text必须仅在主线程中使用)

有人知道这种问题,也许知道解决方法? 感谢您的帮助

编辑

第一件事是,标签第一次更改,但是当我再次按下按钮时仍然不更新标签。 (其目的是能够通过互联网记录字符串的历史记录,因此,当将其他信息分配给Table tableau [4]并进行其他更改时,(新的Tableau [3]是最后一个Tableau [4 ])UIlabel.text似乎没有更新)Table Tableau []的供稿很好:)

3 个答案:

答案 0 :(得分:1)

URLSession.shared.dataTask(在后​​台线程中运行,因此任何ui更新都应嵌入其中

 DispatchQueue.main.async { 

                if self.tableau.count >= 5 { // avoid crashes 
                    self.labelMess0.text = self.tableau[4]
                    self.labelMess1.text = self.tableau[3]
                    self.labelMess2.text = self.tableau[2]
                    self.labelMess3.text = self.tableau[1]
                    self.labelMess4.text = self.tableau[0]
                }
 }

答案 1 :(得分:1)

您在线程方面遇到问题

@IBAction func sendButtonTapped(_ sender: AnyObject) {
    [...]
    // Object that holds http request information
    let request = NSMutableURLRequest(url:myUrl! as URL)
    // set cookies, body, headers, whatever
    [...]

    [1]
    // now create download handler
    let downloadHandler = URLSession.shared.dataTask(
        with: request as URLRequest
    ) {
        [3]
        [some function to be executed when download finishes]
    }
    [2]
    // start download
    downloadHandler.resume()


    // use of variable that isn't initialised yet!
    if(self.tableau.count != 0){
    }
}

流程如下:

  1. 首先创建请求,并在其中填写地址和正文
  2. 您创建下载程序并将其设置为回调[1]
  3. 您启动下载器[2]
  4. [您等待]
  5. 背景线程调用您的回调[3]

(请注意,您无法在后台线程上编辑UI元素)

因此您的代码应如下:

@IBAction func sendButtonTapped(_ sender: AnyObject) {
        // Send HTTP GET Request

              // Define server side script URL
              let scriptUrl = "https://lora-thomas-slave.data.thethingsnetwork.org/api/v2/query?last=7d"

              // Create NSURL Ibject
              let myUrl = NSURL(string: scriptUrl);

              // Creaste URL Request
               let request = NSMutableURLRequest(url:myUrl! as URL);

              // Set request HTTP method to GET. It could be POST as well
               request.httpMethod = "GET"

              // Or it could be a single Authorization Token value
               request.addValue("application/json", forHTTPHeaderField: "Accept")
               request.addValue("key ttn-account-v2.*************", forHTTPHeaderField: "Authorization")

              // Excute HTTP Request
               URLSession.shared.dataTask(with: request as URLRequest) {(data, response, error) in
                   do{
                       // Try to assign Json Lora data into an array of Structured data
                       let donne = try JSONDecoder().decode([Donnee].self, from: data!)

                       // For each data, print the received string
                       let compt: Int = donne.count         //compt = number of json objects
                       var j : Int = 0
                       var chaine: String = " "
                       var x : Int = 0
                       for i in donne{
                           if (j > (compt-6)){
                               chaine = i.time.split(separator: "T")[0]  + " " + i.time.split(separator: "T")[1].split(separator: ".")[0] + " : " + i.receivedString
                               self.tableau.append(chaine)
                               x += 1
                           }
                           j += 1
                       }
                       DispatchQueue.main.async { 
                            if(self.tableau.count != 0){
                                self.labelMess0.text = self.tableau[4]
                                self.labelMess1.text = self.tableau[3]
                                self.labelMess2.text = self.tableau[2]
                                self.labelMess3.text = self.tableau[1]
                                self.labelMess4.text = self.tableau[0]
                             }
                       }
                   }catch{
                       print("error !")
                   }
               }.resume()
        }

答案 2 :(得分:1)

就像我在评论中提到的那样,您需要使用

在主线程上进行UI更新
DispatchQueue.main.async { 
    self.labelMess0.text = self.tableau[4]
    self.labelMess1.text = self.tableau[3]
    self.labelMess2.text = self.tableau[2]
    self.labelMess3.text = self.tableau[1]
    self.labelMess4.text = self.tableau[0]
}

您的第二个问题是,当再次按下按钮时,新结果将附加到数组中,这意味着它将位于5-9位置,因此您需要先清除数组,self.tableau.removeAll()

直接在sendButtonTapped中进行操作,或者最好在闭包中首先进行操作,这样如果请求失败,旧值就不会消失。