Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I solve this: UILabel.text must be used from main thread only

So I am trying to update the UI in my application. What happens is that the labels get updated but when they do not keep their own value but sometimes take the value of the other label. Also, I get the message that the label should be used from main thread only, how do I solve this?

Here is my code:

let queue = DispatchQueue(label: "update")
queue.async {
   for s in self.fietshare.stands {
      for b in s.bikes {
         lbAvailable.text = "Available Bikes: " + String(s.id) +  "  " + String( s.bikes.count) // shows too big numbers
         nrOfAvailable.text =  String(b.distance) + "M"
         annotationView.layoutIfNeeded()
         print(s.id)
         print("Nr of bikes")
         print(s.bikes.count)
      }
   }
}

DispatchQueue.main.async {
   self.view.backgroundColor = . black;
   self.view.layoutIfNeeded()
}

if (Thread.current.isMainThread) {
    print("Main thread")
}
like image 436
Tator Avatar asked Dec 31 '22 13:12

Tator


1 Answers

Try this

let queue = DispatchQueue(label: "update")

queue.async {

    var available = ""
    var nrOfAvailable = ""
    for s in self.fietshare.stands{
        for b in s.bikes {
            available = available + "Available Bikes: " + String(s.id) +  "  " + String( s.bikes.count) // shows too big numbers
            nrOfAvailable = String(b.distance) + "M"

            print(s.id)
            print("Nr of bikes")
            print(s.bikes.count)
        }
    }

    // UPDATE UI after all calculations have been done
    DispatchQueue.main.async {
        lbAvailable.text = available
        nrOfAvailable.text = nrOfAvailable
        annotationView.layoutIfNeeded()

        self.view.backgroundColor = . black;
        self.view.layoutIfNeeded()
    }
}

Explanation:

  • you start an asynchronous task with queue.async
  • inside this "job in the background" you start a for loop
  • this for loop needs to update some UI bits
  • do this in the Main Thread, that's why we switch that part back to the Main Thread

Explanation 2:

  • UIKit is not Thread Safe. That means that is expecting all changes to come from the Main Thread and be synchronous (one after the other). So no "locking mechanism" or protection is in place. If you try to change a Label from different threads at the same time, weird things can happen due to race conditions, like parts of the label being changed, in different order, etc.
like image 81
Diego Freniche Avatar answered Feb 05 '23 19:02

Diego Freniche