Приостановить выполнение Swift-кода во время загрузки онлайн-данных?

Я делаю простое приложение для церкви, которая извлекает случайное имя из базы данных MySQL членов и устанавливает текст кнопки «получить имя» к имени члена. В основном это работает, но самое первое нажатие кнопки не изменяет текст кнопки, хотя печати показывают, что он правильно извлекает имя из базы данных. Как я неоднократно нажимаю, иногда текст меняется, а иногда нет. Я думаю, что это может быть потому, что данные еще не загружены, и Swift переходит к следующему фрагменту кода слишком быстро. Есть ли правильный способ отложить это до загрузки данных? Спасибо!

Вот код приложения:

//
//  ViewController.swift
//  Grace Tabernacle Prayer App
//
//  Created by Nico Pampaloni on 1/14/17.
//  Copyright © 2017 Pampaloni Code. All rights reserved.
//
// Simple app to retrieve a random name from a MySQL database and    display that name as the button text.


import UIKit

class ViewController: UIViewController {



    @IBAction func buttonPressed(_ sender: UIButton) {
        // set URL of php script as NSURL
        let scriptUrl = "https://gtinternal.com/api/getname.php"
        let myUrl = NSURL(string: scriptUrl);
        let request = NSMutableURLRequest(url:myUrl! as URL);
        // use HTTP GET to retreive request data
        request.httpMethod = "GET"

        // store the GET response and convert to a String
        let task = URLSession.shared.dataTask(with: request as URLRequest) {
            data, response, error in

            if error != nil
            {
                print("error=(error)")
                return
            }

            let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)!

            let memberName = responseString as String

            print(responseString)

            // change Button text to retrieved string
            sender.setTitle(memberName, for: .normal)
        }

        task.resume()  
    }

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

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

1 ответ

  1. Проблема в том, что код внутри задачи выполняется асинхронно как часть блока закрытия. Это означает, что он не выполняется в главном потоке. Затем вы попытаетесь обновить пользовательский интерфейс из фонового потока, что даст неожиданные результаты. Всегда помещайте код пользовательского интерфейса в основной поток. При установке заголовка на senderпоместите этот код в блок для выполнения в главном потоке.

    DispatchQueue.main.async {
      // change Button text to retrieved string
      sender.setTitle(memberName, for: .normal)
    }