【问题标题】:How to fix a value return nil in Swift?如何在 Swift 中修复返回 nil 的值?
【发布时间】:2020-07-21 15:06:07
【问题描述】:

我想从 JSON Data 中的数据创建 TableView,但是当我尝试获取该值时,它总是在第二次打印时返回 nil。 你能解释一下并给我一些关于这个问题的建议吗? 在问这个问题之前我已经很努力了,但我真的很陌生:(

最好的问候,

import UIKit

struct News: Decodable {
    var status:String
    var totalResults:Int
    var articles:[Articles]?
}

struct Articles: Decodable{
    var source:Source?
    var title:String?
    var description:String?
    var urlToImage:String?
    var publishedAt:String?

}

struct Source: Decodable{
    var name:String?

}

class NewsViewController: UIViewController{
      var a = [String]()

    @IBOutlet weak var TableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        //Hit API
       let url = URL(string: "http://newsapi.org/v2/top-headlines?country=th&category=technology&apiKey=2b27ab9b590041a6a6dcdf4ef94a0a33")

        URLSession.shared.dataTask(with: url!) { (data, response, error) in
            if error == nil {

                do {
                    let result = try JSONDecoder().decode(News.self,from: data!)
                  let totalresult = result.articles!.count


                 for result in result.articles!{
                     let titleUnWrapped: String = result.title ?? ""
                     let urlToImageUnWrapped: String = result.urlToImage ?? ""
                    self.a.append(titleUnWrapped)
                   // print(self.a) <<<<<<<<<<<<<<<<<<<<<<<<< Work
                    }
                } catch {
                    print("ERROR")
                }

        }

        }.resume()

       print(self.a) //Return nil <<<<<<<<<<<<<<<<<<<<<<<<< Not Work
}
}

【问题讨论】:

  • 您的第二个打印语句在您的 api 调用之后立即执行,但在该 api 调用检索数据并完成之前 - 所以它仍然是空的。仅在检索到数据后才调用完成闭包内的打印语句,从而显示正确的结果。 api 调用是异步的,所以它会继续执行它的工作,但不会阻塞代码的执行流程,因此在 a 仍然为空时执行第二个打印语句。
  • 非常感谢 Magnas 的建议!,另一个问题是我怎样才能让它等到完全检索到数据然后调用第二个函数所以它不返回 nil?我已经尝试过 dispatchgroup 但它似乎对我不起作用:(

标签: ios json swift


【解决方案1】:

我认为问题只是缺乏闭包经验。该行的这一部分: URLSession.shared.dataTask(with: url!) 向您的 url 发送请求(即某处的某个远程服务器),但不知道究竟需要多长时间才能得到响应。它不是等待和阻塞主线程(无响应的 UI 和糟糕的用户体验),而是将其请求 在主线程之外,并且您的代码在等待时继续执行。这就是最后一个打印语句失败的原因,但这意味着用户仍然可以通过滚动表格或其他方式与您的应用进行交互。

但是当最终从远程数据源收到响应时,它会被传递到您的闭包中并执行内部代码。因此,此时您要么成功(数据良好),要么失败(检查响应和错误)。如果您有良好的数据,那么您可以将其传递给一些外部函数以继续使用它。例如

class NewsViewController: UIViewController{

   var a = [String]()

    @IBOutlet weak var TableView: UITableView!

    override func viewDidLoad() {
       super.viewDidLoad()

       //Hit API
       let url = URL(string: "http://newsapi.org/v2/top-headlines?country=th&category=technology&apiKey=2b27ab9b590041a6a6dcdf4ef94a0a33")
       URLSession.shared.dataTask(with: url!) { (data, response, error) in
          if error == nil {
             do {
                let result = try JSONDecoder().decode(News.self,from: data!)
                let totalresult = result.articles!.count

                for result in result.articles! {
                   let titleUnWrapped: String = result.title ?? ""
                   let urlToImageUnWrapped: String = result.urlToImage ?? ""
                   self.a.append(titleUnWrapped)
                   // print(self.a) <<<<<<<<<<<<<<<<<<<<<<<<< Work
                   self.doSomethingWithResult(with: a) //<<<< Pass `a` out of the closure
                }
             } catch {
                print("ERROR")
             }
           } else {
              // Error is not nil so do something...
              print("ERROR: \(error)")
        }.resume()
     }

     // This method is called from inside the closure only when you have good
     // data returned from your api call.
     func doSomethingWithResult(with goodData: [String]) {
        // Use `a`...
     }
}

因此您不必担心尝试过早访问数据或等待数据完成,在您获得完整响应(无论是好的响应还是坏的响应)之前,不会调用闭包。希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-09
    • 2019-02-18
    • 1970-01-01
    • 1970-01-01
    • 2017-07-09
    • 2017-04-24
    相关资源
    最近更新 更多