gpt4 book ai didi

ios - 这段代码中的 'DispatchQueue.main.async' 和 'completed: @escaping () -> ()' 是什么意思?

转载 作者:行者123 更新时间:2023-11-28 09:50:45 26 4
gpt4 key购买 nike

基本上这是一个简单的项目,涉及一个 TableView ,该 TableView 根据从 api 中从 JSON 解析的数据进行更新。我相信 DispatchQueue.main.asynccompleted: @escaping () -> () 与更新/重新加载 tableview 有关,但我不确定它是如何实现的作品。如果能解释一下这两者的作用,我们将不胜感激。

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var tableView: UITableView!

var heroes = [HeroStats]()

override func viewDidLoad() {
super.viewDidLoad()
fetchData {
print("Success")
}
}

func fetchData(completed: @escaping () -> ()) {

let jsonUrlString = "https://api.opendota.com/api/heroStats"
guard let url = URL(string: jsonUrlString) else { return }

URLSession.shared.dataTask(with: url) { (data, response, error) in

guard let data = data else { return }

if error == nil {
do {
let heroes = try JSONDecoder().decode([HeroStats].self, from: data)
DispatchQueue.main.async {
completed()
}
} catch let error {
print(error)
}
}
}.resume()
}
}

最佳答案

  1. DispatchQueue.main.async { ... } 表示“在主队列的大括号内运行以下代码”(这是所有 UI 更新必须运行的地方)。 URLSession 闭包和委托(delegate)方法在专用的 URLSession 队列上运行,但 UI(和模型)更新应该发生在主队列上。

    仅供引用,将代码分派(dispatch)到另一个队列的两种常见方法是asyncsync。它们非常相似,但是 async 异步运行(即 async 调用之后的代码不会等待主线程完成调用 completed 在继续之前),并且 sync 同步运行(即它会等待)。在这种情况下,让 URLSession 队列等待主队列完成是没有意义的,因此 async 是合适的。

  2. completed: @escaping () -> () 表示:

    • fetchData有一个参数,叫做completed
    • 此参数是一个“闭包”(即调用者可以提供的一段匿名代码;有关详细信息,请参阅 The Swift Programming Language: Closures);
    • 这个闭包本身不接受任何参数,也不返回任何东西;和
    • 此闭包“转义”(意味着它不一定会在 fetchData 方法返回时运行)。

    因此,您可以像这样传递要调用的代码块(当您在 dataTask 闭包中看到 completed() 时):

    fetchData(completed: {
    print("Success")
    self.tableView.reloadData() // make sure to reload table when request is done
    })

    但是,您的示例使用“尾随闭包”语法,其中最终闭包(在本例中是唯一的闭包)可以作为参数省略,并在 fetchData 调用之后添加,导致相同的行为(但语法更简洁):

    fetchData {
    print("Success")
    self.tableView.reloadData()
    }

    或者,甚至更好:

    fetchData { [weak self] in
    print("Success")
    self?.tableView.reloadData()
    }
  3. 在一个不相关的观察中,您永远不会更新您的 heroes 属性。至少,您应该:

    URLSession.shared.dataTask(with: url) { data, response, error in
    guard let data = data, error == nil else {
    print(error ?? "Unknown error")
    return
    }

    do {
    let heroes = try JSONDecoder().decode([HeroStats].self, from: data)
    DispatchQueue.main.async {
    self.heroes = heroes
    completed()
    }
    } catch let error {
    print(error)
    }
    }.resume()

    请注意,您要更新async 闭包self.heroes 属性,以确保您不会更新该属性从后台线程。数组不是线程安全的,通过在主线程上更新该属性,可以避免任何竞争条件。

    还有许多其他改进我可以建议(使用 weak 引用 dataTask 中的 self;向您的 completed 添加一个参数 闭包,以便调用者知道它是否成功,如果不成功则显示警告等),但以上是我建议的最低限度。

关于ios - 这段代码中的 'DispatchQueue.main.async' 和 'completed: @escaping () -> ()' 是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48699048/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com