Swift - Почему при извлечении данных из JSON перед отображением данных отображается пустая задержка TableView? - PullRequest
0 голосов
/ 15 сентября 2018

Редактировать: Пожалуйста, игнорируйте старые ответы. Я не могу создать новый вопрос, мой обвиняемый был заблокирован. Поэтому я отредактировал этот вопрос новым названием в заголовке.

Как я могу получить результаты своих данных, как только я просмотрю загрузку таблицы?

Вот фрагмент моего кода. Может ли кто-нибудь помочь мне понять асинхронную часть, которая заставляет мой код извлекать данные и возвращать мне результат с опозданием.

`

let apiUrl = "https://shopicruit.myshopify.com/admin/products.json? 
  page=1&access_token=c32313df0d0ef512ca64d5b336a0d7c6"

var myRowProduct : String = ""

var productArrayName : [String] = []

var productsPassedOver : [String] = []


override func viewDidLoad() {
    super.viewDidLoad()

    getFullProductsJson(url: apiUrl, tag1: myRowProduct){array, err in
        if err != nil {
            print("ERROR 2")
        }else{
            self.productsPassedOver = array


            self.tableView.reloadData()


            print("productsPassedOver \(self.productsPassedOver)")
        }
    }
}



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



override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "ProductCell", for: indexPath)

    cell.selectionStyle = .none

    cell.textLabel?.text = "\(indexPath.row + 1). " + productsPassedOver[indexPath.row] + "\n" //label are in every single cell. The current text that is displayed by the label

    cell.textLabel?.numberOfLines = 0; //removes any limitations on the number of lines displayed        

    return cell
}



//Networking JSON
func getFullProductsJson(url: String, tag1: String, completion: @escaping ([String], Error?) -> ()) {

    Alamofire.request(url, method: .get).responseJSON {
        response in

        //response.result.value comes back as an optional so use ! to use it. Also value have datatype of Any? thats why we JSON casting
        if response.result.isSuccess{

            let fullJSON : JSON = JSON(response.result.value!)

            let finalArrayOfProductS = self.updateTagProductData(json: fullJSON, tag2: tag1)

            completion(finalArrayOfProductS, nil)
        }
        else{
            print("Error JSON")
        }
    }
}



//JSON parsing, deal with formatting here
func updateTagProductData(json : JSON, tag2: String) -> [String]{

    let tagClicked = tag2

    var nbOfProducts : Int = 0
    nbOfProducts = json["products"].count

    var inventoryAvailableTotal : Int = 0

    var nbOfVariants : Int = 0


    for i in 0..<nbOfProducts {

        let tagsGroup : String   = json["products"][i]["tags"].stringValue

        let productName : String = json["products"][i]["product_type"].stringValue

        nbOfVariants = json["products"][i]["variants"].count



        if tagsGroup.contains(tagClicked){
            for j in 0..<nbOfVariants{
                inventoryAvailableTotal += json["products"][i]["variants"][j]["inventory_quantity"].int!
            }

            print("\(tagClicked) tag exist in the product \(i): \(productName)")
            print("inventorytotal \(inventoryAvailableTotal)")

            productArrayName.append("\(productName): \(inventoryAvailableTotal) available")
        }
    }

    return productArrayName
  }
 }

`

1 Ответ

0 голосов
/ 15 сентября 2018

Это функция, которая делает что-то в фоновом режиме и немедленно возвращает результат, а когда она завершает работу, вызывает ваш обработчик завершения.

Поэтому вполне естественно, что эта функция напрямую переходит к return finaleNbOfRowsInProductsListPage.

Ваше решение состоит в том, что функция не должна возвращать значение, но она должна принять обработчик завершения и вызывать его после завершения.Это стиль передачи продолжения .

func getFullProductsJson(url: String, tag1: String, completion: @escaping (Int?, Error?) -> ()) {
    Alamofire.request(url, method: .get).responseJSON {
        response in
        ...
        // When you are done
        completion(finaleNbOfRowsInProductsListPage, nil)
    }
}

Также обратите внимание, чтобы попытаться избежать установки большого количества переменных, попытаться сделать все параметром или возвращаемым значением из функции, этолегче отлаживать.Например, попробуйте сделать список как параметр, который передается в обработчик завершения, а не как переменную-член вашего контроллера представления, сделайте эту переменную-член только для списка, который готов к отображению.

func getFullProductsJson(url: String, tag1: String, completion: @escaping (Products?, Error?) -> ()) {
    Alamofire.request(url, method: .get).responseJSON {
        response in
        ...
        // When you are done
        completion(products, nil)
    }
}

var products: [Product] = []

func refreshData() {
    getFullProductsJson(url: "YOUR_URL_HERE", tag1: "TAG") {
        // Try to use [weak self], also,  read about Automatic Reference Counting
        productsNullable, error in
        if let products = productsNullable {
            // Alamofire calls your callback on a background thread
            // So you must return to the main thread first when you want
            // to pass the result to any UI component.
            DispatchQueue.main.async {
                self?.products = products
                self?.tableView.reloadData()
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...