Aktualisierung Label nachdem Background Task Daten aus Internet ermittelt hat

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

Aufgrund der Corona-Krise: Die Veröffentlichung von Stellenangeboten und -gesuchen ist bis 31.12.2020 kostenfrei. Das beinhaltet auch Angebote und Gesuche von und für Freischaffende und Selbstständige.

  • Aktualisierung Label nachdem Background Task Daten aus Internet ermittelt hat

    Hallo,

    ich versuche mich gerade in Swift einzuarbeiten in dem ich einen Udemy Kurs zu Swift durcharbeite und einige Tutorials aus dem Internet probiere. Jetzt habe ich ein konkretes Problem und komme nicht so recht weiter und bin dabei auf dieses Forum gestoßen und hoffe das Ihr mir vielleicht auf die Sprünge helfen könnt :)

    Hier nun die Beschreibung zu meinem Problem.

    Ich habe einen Task der Daten (Währungsdaten) aus dem Internet lädt und in JSON Format zurück liefert. Ich parse die Daten und möchte dann den Wert, z.B. Kurs EUR zu Dollar, in einem Label anzeigen.
    In meinem ersten Versuch habe ich in dem Task, nachdem ich die Daten ermittelt habe, im Label angezeigt. Das funktioniert im Prinzip, führt aber in Xcode zu folgender Warnung (purple):

    Quellcode

    1. UILabel.text must be used from main thread only


    Wenn ich das "Problem" google, ist mir im Prinzip auch klar was hiermit gemeint ist, man sollte das UI nicht blockieren mit Background Task die unter Umständen sehr lange dauern.

    Wenn ich die Daten nicht im Data Task setze, sondern danach, habe ich ein zeitliches Problem, die Abfrage der Daten aus dem Internet dauert z.B. 2s, dann ist das setzen der Label schon durch und wird nicht
    mehr aktualisiert wenn der Background Data Task die Daten geholt hat.

    Hier mal ein Auszug aus dem Code (ViewController.swift):


    Brainfuck-Quellcode

    1. import UIKit
    2. class ViewController: UIViewController {
    3. @IBOutlet weak var currency_EUR_USD: UILabel!
    4. @IBOutlet weak var abfrageDatum: UILabel!
    5. var valueEUR_USD: Double = 0.0
    6. var valueUSD_EUR: Double = 0.0
    7. var valueAbfrageDatum: String = ""
    8. override func viewDidLoad() {
    9. super.viewDidLoad()
    10. //self.view.backgroundColor = .lightGray
    11. // Do any additional setup after loading the view.
    12. // API Endpoint: https://free.currconv.com/api/v7/convert?q=USD_EUR,EUR_USD&compact=ultra&apiKey=4952f1f9652ee73bff5e
    13. // Reference: https://www.currencyconverterapi.com
    14. let urlString = "https://free.currconv.com/api/v7/convert?q=USD_EUR,EUR_USD&compact=ultra&apiKey=4952f1f9652ee73bff5e"
    15. let url = URL(string: urlString)
    16. let session = URLSession.shared
    17. let dataTask = session.dataTask(with: url!) { [self] (data, reponse, error) in
    18. // check for errors
    19. if error == nil && data != nil {
    20. // parse json
    21. do {
    22. // Aktuelles Abfrage Datum ermitteln und formatieren
    23. // Referenz: https://www.ralfebert.de/ios/swift-dateformatter-datumsangaben-formatieren/
    24. let formatter = DateFormatter()
    25. formatter.locale = .init(identifier: "de")
    26. formatter.dateStyle = .medium
    27. formatter.timeStyle = .medium
    28. let dateFormattedString = formatter.string(from: Date())
    29. valueAbfrageDatum = dateFormattedString
    30. let currency: Currency = try! JSONDecoder().decode(Currency.self, from: data!)
    31. valueEUR_USD = currency.EUR_USD
    32. valueUSD_EUR = currency.USD_EUR
    33. // Set data to label --> Force Warning here!!!!
    34. abfrageDatum.text = valueAbfrageDatum
    35. currency_EUR_USD.text = String(valueEUR_USD)
    36. print("Abfrage@ \(dateFormattedString)")
    37. print ("1€ = \(currency.EUR_USD)$")
    38. print ("1$ = \(currency.USD_EUR)$")
    39. print("------------------------------------------------------------------------------")
    40. print ("This is JSON result --> \(currency)")
    41. }
    42. }
    43. }
    44. // Make the API call
    45. dataTask.resume()
    46. // Set data to Label
    47. abfrageDatum.text = valueAbfrageDatum
    48. currency_EUR_USD.text = String(valueEUR_USD)
    49. }
    50. }
    Alles anzeigen

    Frage:

    Wie kann ich das Label mit den Daten aus dem dataTask() automatisch aktualisieren wenn dieser fertig ist?

    Gruß

    Ralf
  • Hallo zusammen,

    irgendwie schon komisch .. wenn man sich das "Problem von der Seele" geschrieben hat fällt einem vermutlich die Lösung auf die Füße ;)
    Ich habe nun folgendes, nach weiterem stöbern bei Stackoverflow, gefunden und im dataTask() eingebaut:

    Quellcode

    1. DispatchQueue.main.async {
    2. abfrageDatum.text = valueAbfrageDatum
    3. currency_EUR_USD.text = String(valueEUR_USD)
    4. }
    Es funktioniert und Xcode gibt auch keine Warnung mehr aus 8o

    Es wäre allerdings toll wenn mir einer der vielen Gurus in diesem Forum mir sagen könnte ob das der richtige Weg ist oder ob ich hier auf dem "Holzweg" bin und es nur zufällig funktioniert.

    Gruß

    Ralf
  • ralfb schrieb:

    Wenn ich das "Problem" google, ist mir im Prinzip auch klar was hiermit gemeint ist, man sollte das UI nicht blockieren mit Background Task die unter Umständen sehr lange dauern.
    Willkommen im Forum, Ralf!

    Jein, Du bist mit der o.g. Aussage auf der richtigen Fährte, aber konkret geht es darum, dass Änderungen der UI eben nur im Main-Thread durchgeführt werden dürfen. Da aus dem von Dir genannten Grund - mit dem JSON-Download nicht die UI zu blockieren - eine Task asynchron läuft, kannst Du nicht nach ihrem Aufruf das Ergebnis verarbeiten. Du musst also im Download-Thread nach Empfang der Daten eine Aktualisierung im Main-Thread erzwingen. Dafür gibt es z. B. die folgende Möglichkeit:

    Quellcode

    1. DispatchQueue.main.async {
    2. ...
    3. }
    Du bist also genau richtig unterwegs, Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.