2

I was asked this question in an interview. I want to know what will be the case if we give UILabel to background thread.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Srikanth Adavalli
  • 665
  • 1
  • 10
  • 25

2 Answers2

2

The short answer is "results are undefined", or "Bad things". UIKit is not thread-safe, so you don't know, but it's not going to be good.

I've seen UI changes take a LOOOOOONNNG time to take effect, if ever, and I've seen crashes.

The better answer is "Don't do that."

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • In ios 9 you will get an exception if you modify UI elements on another thread – Paulw11 Apr 06 '16 at 03:30
  • @Paulw11, Really? Guaranteed? What's the mechanism that throws an exception? – Duncan C Apr 06 '16 at 10:25
  • You get an exception message that says something like "you are modifying the UI on a background thread" – Paulw11 Apr 06 '16 at 11:25
  • Strangely I can't reproduce it now, but I have definitely received exceptions when modifying UI on the wrong queue. – Paulw11 Apr 06 '16 at 11:43
  • 1
    @Paulw11, like I said, in my experience the results are undefined, ranging from delayed update, to no update, to causing a crash. It would be good if Apple were to add a check for UIKit calls from the background and a forced exception in ALL cases, at least for debug builds. That would save us developers a lot of time. – Duncan C Apr 06 '16 at 14:00
2

It depends on whether label is in the view hierarchy or not. General rule is that the code running by a background thread should not trigger any UI updates such as view.addSubview or label.setNeedsLayout etc, then it is safe to play around with your label in that thread.

You should be careful though, once label is added to a view, even updating label.text in a background thread is dangerous as it will invalidate its superview's layout so the UI will get updated within that thread.

Let's say your custom UILabel class is doing some time consuming operation in its constructor which has nothing to do with the UI:

class MyFatLabel: UILabel {
  override init(frame: CGRect) {
    super.init(frame: frame)
    self.text = "Lorem ipsum"        
    self.readDataFromDisk() // will block the main thread.
  }
}

Then, you can initialize that label in a separate thread and add it into a view in the main(UI) thread so the user interaction with the UI won't get blocked:

dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) {
  let label = MyFatLabel(frame: CGRectZero)

  dispatch_async(dispatch_get_main_queue()) {
    view.addSubview(label)
  }
}

Long story short, you can initialize new UILabel (or any UIResponder) in a background thread however, you should be changing any of its properties triggering UI updates within the main thread.

Ozgur Vatansever
  • 49,246
  • 17
  • 84
  • 119