Swift 4 - Где в моем вызове API RESTful находится "Фоновая нить?" - PullRequest
0 голосов
/ 14 октября 2018

Моему классу было поручено создать приложение, которое реализует вызовы RESTful API.Мое приложение имеет 2 экрана:

  1. Первый экран, в котором перечислены все типы покемонов (в форме проанализированного JSON)
  2. Второй экран, в котором перечислены подробности (в форме проанализированного JSON)JSON) о выбранном типе

В нашей рецензии на проект перед нами стоит указание фрагмента кода с " фоновым потоком ".Я не уверен, где в моем коде находится " фоновая нить ".

Я нашел этот ответ StackOverflow , который указывает, что код в DispatchQueue.global(qos: .background).async {}работать в фоновом потоке, в то время как код в DispatchQueue.main.async {} выполняется в основном потоке.Тем не менее, у меня есть только DispatchQueue.main.async {} и нет DispatchQueue.global(qos: .background).async {}.Означает ли это, что у меня нет фоновой темы?Должен ли я сейчас реализовать это?Или все, что не находится в основном потоке, по умолчанию работает в фоновом потоке?

Код для ViewController.swift , в котором перечислены все типы Pokemon, приведен ниже:

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

Какая часть этого кода является фоновым потоком?

Я знаю, что обычно вам нужно только вызвать основнойпоток при изменении пользовательского интерфейса.Означает ли это, что все выражения do{} в моих примерах находятся в фоновом потоке, за исключением кода в DispatchQueue.main.async {}?

Ответы [ 2 ]

0 голосов
/ 14 октября 2018

Всякий раз, когда вы делаете вызов API и появляется «обработчик завершения», тогда это asynchronous.Поскольку это asynchronous, вам не нужно беспокоиться о том, чтобы поместить его в поток, фреймворк сделает это за вас.

Например, если вы поместите какой-либо круговой индикатор выполнения на ваш вид или что-нибудь анимированное, вы увидите, что ваш вызов URLSession.shared.dataTask не остановит анимацию.

Вам все еще нужно позвонить DispatchQueue.main.async, потому что при вводе кода обработчика завершения вы находитесь в потоке, который dataTask создал.

0 голосов
/ 14 октября 2018

Все запросы и код внутри

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

выполняются в фоновом потоке, другие DispatchQueue.main.async должны быть только для пользовательского интерфейса, и вы правильно настроили эту структуру

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


рассмотрите этот код внутри viewDidLoad

 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!)

заблокирует основной поток, так как Data(contentsOf работает в потоке, в который вы его поместилитак что у вас есть 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() 

, поэтому перед использованием любого метода выдолжен предварительно знать, где он будет выполняться в вашем текущем потоке, что если основной он будет заблокирован до завершения запроса, а если нет, то обернуть его обратным вызовом insid DispatchQueue.main.async` для любых обновлений пользовательского интерфейса

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...