当前位置: 首页 > 知识库问答 >
问题:

Swift 4-我的RESTful API调用中的“后台线程”在哪里?

朱华皓
2023-03-14

我们班的任务是制作一个实现RESTful API调用的应用程序。我的应用程序有两个屏幕:

  1. 列出所有口袋妖怪类型的第一个屏幕(以解析的JSON形式)
  2. 列出有关所选类型的详细信息(以解析的JSON形式)的第二个屏幕

在这个项目的编写过程中,我们的任务是用“后台线程”指示代码段。我不确定“后台线程”在我的代码中的位置。

我找到了这个StackOverflow答案,它表示DispatchQueue中的代码。全局(qos:。后台)。异步{}在后台线程中运行,而代码在DispatchQueue.main中运行。异步{}在主线程中运行。然而,我只有DispatchQueue.main。异步{}和无调度队列。全局(qos:。后台)。异步{}。这是否意味着我没有背景线程?我现在必须实施吗?或者不是主线程中的所有内容都默认在后台线程中运行?

列出所有口袋妖怪类型的ViewController.swift代码如下:

import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    final let url = URL(string: "https://pokeapi.co/api/v2/type/")
    private var results = [Movetype]()
    @IBOutlet var tableView: UITableView!
    var sequeIdentifiers = ["Normal", "Fighting", "Flying", "Poison", "Ground", "Rock", "Bug", "Ghost", "Steel", "Fire", "Water", "Grass", "Electric", "Psychic", "Ice", "Dragon", "Dark", "Fairy", "Unknown", "Shadow"]

    override func viewDidLoad() {
        super.viewDidLoad()
        downloadJson()
        // Do any additional setup after loading the view, typically from a nib.
    }

    func downloadJson() {
        guard let downloadURL = url else { return }

        URLSession.shared.dataTask(with: downloadURL) { data, urlResponse, error in
            guard let data = data, error == nil, urlResponse != nil else {
                print("something is wrong")
                return
            }
            print("downloaded")
            do
            {
                let decoder = JSONDecoder()
                let downloaded_movetypes = try decoder.decode(Results.self, from: data)
                self.results = downloaded_movetypes.results
                DispatchQueue.main.async { // <- ********* MAIN THREAD *********
                    self.tableView.reloadData()
                }
            } catch {
                print("something wrong after downloaded")
            }
        }.resume()
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return results.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "MovetypeCell") as? MovetypeCell else { return UITableViewCell() }

        cell.Name_Label.text = results[indexPath.row].name.capitalized

        let img_name = sequeIdentifiers[indexPath.row].lowercased() + ".png"

        print(img_name)

        cell.Img_View.image = UIImage(named: img_name)

        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        //performSegue(withIdentifier: sequeIdentifiers[indexPath.row], sender: self)
        let detailVc = self.storyboard?.instantiateViewController(withIdentifier: "Fighting")  as! Fighting
        detailVc.subType = sequeIdentifiers[indexPath.row].lowercased()
        self.navigationController?.pushViewController(detailVc, animated: true)
    }

}

哪一部分是背景线程?

我的应用程序第二个屏幕的代码Fighting.swift列出了所选类型的详细信息,如下所示:

 var subType = ""
    override func viewDidLoad() {
        super.viewDidLoad()
        self.title = subType.capitalized
        let jsonUrlString = "https://pokeapi.co/api/v2/type/\(subType)/"
        guard let url = URL(string: jsonUrlString) else { return }

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

            guard let data = data else { return }

            do {
                // Get fighting JSON data
                let fighting_json = try JSONDecoder().decode(fighting.self, from: data)
                let detail_json = try JSONDecoder().decode(detailData.self, from: data)

                 print("Codementor == \(detail_json.damage_relations)")

                print(fighting_json.damage_relations?.double_damage_from?.compactMap({ $0.name?.capitalized }) ?? "Bad data")

                // Create Array: Double Damage From
                let double_damage_from_fighting_array = fighting_json.damage_relations?.double_damage_from?.compactMap({ $0.name?.capitalized }) ?? ["Bad data"]

                // Create Array: Double Damage To
                let double_damage_to_fighting_array = fighting_json.damage_relations?.double_damage_to?.compactMap({ $0.name?.capitalized }) ?? ["Bad data"]

                // Create Array: Half Damage From
                let half_damage_from_fighting_array = fighting_json.damage_relations?.half_damage_from?.compactMap({ $0.name?.capitalized }) ?? ["Bad data"]

                // Create Array: Half Damage To
                let half_damage_to_fighting_array = fighting_json.damage_relations?.half_damage_to?.compactMap({ $0.name?.capitalized }) ?? ["Bad data"]

                // Create Array: No Damage From
                let no_damage_from_fighting_array = fighting_json.damage_relations?.no_damage_from?.compactMap({ $0.name?.capitalized }) ?? ["Bad data"]

                // Create Array: No Damage To
                let no_damage_to_fighting_array = fighting_json.damage_relations?.no_damage_to?.compactMap({ $0.name?.capitalized }) ?? ["Bad data"]

                DispatchQueue.main.async { // <- ***** MAIN THREAD ******

                    // Print Label: Double Damage From
                    self.double_damage_from_fighting_Label.text = double_damage_from_fighting_array.joined(separator: ", ")

                    // Print Label: Double Damage To
                    self.double_damage_to_fighting_Label.text = double_damage_to_fighting_array.joined(separator: ", ")

                    // Print Label: Half Damage From
                    self.half_damage_from_fighting_Label.text = half_damage_from_fighting_array.joined(separator: ", ")

                    // Print Label: Half Damage To
                    self.half_damage_to_fighting_Label.text = half_damage_to_fighting_array.joined(separator: ", ")

                    // Print Label: No Damage From
                    self.no_damage_from_fighting_Label.text = no_damage_from_fighting_array.joined(separator: ", ")

                    // Print Label: No Damage To
                    self.no_damage_to_fighting_Label.text = no_damage_to_fighting_array.joined(separator: ", ")

                }

            } catch let jsonErr {
                print("Error serializing json:", jsonErr)
            }
            }.resume()
    }
}

该代码的哪一部分是后台线程?

我知道,在更改UI时,通常只需要调用主线程。这是否意味着在我的示例中,除了DispatchQueue.main中的代码外,do{}语句中的所有内容都在后台线程中。异步{}?

共有2个答案

佟英武
2023-03-14

里面的所有请求和代码

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

在后台线程、其他DispatchQueue.main中运行。async应仅为UI,如果设置正确,则使用此结构

DispatchQueue.global(qos: .background).async {
    print("This is run on the background queue")

    DispatchQueue.main.async {
        print("This is run on the main queue, after the previous code in outer block")
    }
}

当你想运行一个长的本地/远程任务时,你希望它在后台线程(这里是全局队列)中,它将等同于你当前的代码,但它会自动切换到后台队列,而无需显式执行,这是URLSession.shared.dataTask的好处

考虑一下这段代码

 let url = URL(string: image.url)
 let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
 imageView.image = UIImage(data: data!)

将阻止主线程作为数据(内容在您放入的线程中运行,因此有2个选项

1-

DispatchQueue.global(qos: .background).async {
    print("This is run on the background queue")

      let url = URL(string: image.url)
      let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch

    DispatchQueue.main.async {
        print("This is run on the main queue, after the previous code in outer block")
        imageView.image = UIImage(data: data!)

    }
}

2-使用您当前的代码加载图像的数据

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

        guard let data = data else { return }

        DispatchQueue.main.async {
        print("This is run on the main queue, after the previous code in outer block")
           imageView.image = UIImage(data: data!)

         }
   }.resume() 

因此,在使用任何方法之前,您应该事先知道它将在当前线程中运行的位置,如果主线程将被阻塞,直到请求完成,如果没有,则将其回调到DispatchQueue.main.async中以进行任何UI更新

邹玄裳
2023-03-14

每当您执行API调用时,如果有一个“完成处理程序”,那么它就是异步的。由于它是异步的,您不必费心把它放在线程中,框架会为您做这件事。

例如,如果您在视图上放置某种圆形进度条或任何动画,您将看到对URLSession.shared的调用。dataTask不会停止动画。

您仍然必须调用DispatchQueue.main.async,因为当输入完成处理程序代码时,您位于dataTask创建的线程上。

 类似资料:
  • 问题内容: 我正在Xcode 9 beta,iOS 11中使用Google Maps。 我收到如下错误输出到日志: 主线程检查器:在后台线程上调用的UI API:-[UIApplication applicationState] PID:4442,TID:837820,线程名称:com.google.Maps.LabelingBehavior,队列名称:com.apple.root.default

  • 问题内容: 我最近了解到,只需添加批注,就可以轻松地使任何会话bean方法异步。 例如 我知道Java EE 7添加了Concurrency Utilities ,但是在Java EE 6中,方法的线程池配置在哪里?有没有办法设置超时时间?是固定线程池吗?一个缓存的?优先级是什么?是否可以在容器中的某个位置进行配置? 问题答案: 我认为可以通过从@Timeout注释的方法调用Future.canc

  • 问题内容: 我对Tomcat不太熟悉,在我看来,它基本上是抽象为cgi服务器,可以在两次调用之间保存JVM -尽管我知道它可以做得多。 我正在寻找一种在Tomcat服务器启动时启动 后台 线程的方法,该方法会定期更新服务器上下文(在我的特殊情况下,这是一个侦听其他服务的心跳并更新可用性信息的线程,但是可以想象得到有多种用途)。 有标准的方法吗?上下文的启动和更新/查询? 指向相关文档和/或代码示例

  • 本文向大家介绍C#中前台线程和后台线程的区别与联系,包括了C#中前台线程和后台线程的区别与联系的使用技巧和注意事项,需要的朋友参考一下 前台线程和后台线程的区别和联系: 1、后台线程不会阻止进程的终止。属于某个进程的所有前台线程都终止后,该进程就会被终止。所有剩余的后台线程都会停止且不会完成。 2、可以在任何时候将前台线程修改为后台线程,方式是设置Thread.IsBackground 属性。 3

  • 我想让一些代码在后台持续运行。我不想在服务中这样做。还有其他可能的方法吗? 我曾尝试在我的活动中调用线程类,但我的活动在后台保留了一段时间,然后就停止了。线程类也停止工作。