Why does it take such a long time for UI to be updated from background thread?

被刻印的时光 ゝ 提交于 2019-11-27 06:28:05

问题


I understand that all UI updates must be done from Main thread.

But purely for the sake of deeper understanding how GCD and dispatch main work:

I have a button that runs a network call and in its completionHandler I eventually do:

self.layer.borderColor = UIColor(red: 255/255.0, green: 59/255.0, blue: 48/255.0, alpha: 1.0).cgColor
self.layer.borderWidth = 3.0

For the color change to happen it takes 6-7 seconds. Obviously if run the above code from main thread it would change the border color immediately.

Question1 even though I don't have ANY other code to run, why doesn't the UI changes happen immediately from the background thread? What is waiting for?

Interesting though is that if I click the button to make the network call and then tap on the textField itself (before the 6-7 seconds), the border color would change immediately.

Is that happening because of:

From the background thread I've updated the model ie change the textField color which queues the UI/view to be updated...but since we're on a background queue, that UI updated could take a few seconds to happen

But then I tapped on the textField right away and forced a super quick read of the textField and all its properties which includes the border—from main thread (actual user touches are always handled through main thread)...which even though are not yet red on the screen, but since it's red on the model it will read from it and change color to red immediately.

Question2: Is that observation correct?

If I don't tap and just wait:

If I tap:


My full code is as below:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    @IBAction func isValid(_ sender: Any) {

        let userEmail = textField.text

        let requestURL = NSURL(string: "https://jsonplaceholder.typicode.com")

        var request = URLRequest(url: requestURL as! URL)

        request.httpMethod = "POST"

        let postString = "Anything"

        request.httpBody = postString.data(using: .utf8)

        let task = URLSession.shared.dataTask(with: request) { data, response, error in

            guard let data = data, error == nil else {
                print("error=\(error)")
                return
            }

            if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
            }

            do {

                let json = try? JSONSerialization.jsonObject(with: data, options: [])

                if let _ = json as? [String: Any] {

                    self.textField.layer.borderColor = UIColor(red: 255/255.0, green: 59/255.0, blue: 48/255.0, alpha: 1.0).cgColor
                    self.textField.layer.borderWidth = 3.0

                }

            } catch let error as NSError {
                print(error)
            }

        }
        task.resume()

    }
    override func viewDidLoad() {
        super.viewDidLoad()
    }

}

回答1:


If you attempt to do UI updates from a background thread, "the results are undefined." The most common effect I've seen is what you describe - very long delays before the update shows up. The second-most common effect I've seen is a crash. The third-most common effect is some sort of drawing artifact.

The results of doing UI updates from a background thread are truly nondeterministic. You've got multiple processor cores accessing the same hardware resources at the same time, and with the exact timing between those accesses being unknowable and infinitely variable. It would be like having a computer with no display but 2 keyboards and 2 mice, and 2 operators editing the same document at the same time. Each person's actions with the keyboard would change the state of the document, and screw up the changes the other person was trying to apply. The cursor would be in the wrong place. The amount of text in the document would be different than expected. The scroll position would be off. etc, etc.

Similarly, if 2 cores are each trying to access hardware resources to do screen refreshes, those accesses will cross and conflict with each other.

As Martin says in his comment, the UIKit code is proprietary, so we can't know the details of what goes wrong. All we know is that bad things happen, so DON'T DO THAT.



来源:https://stackoverflow.com/questions/44931759/why-does-it-take-such-a-long-time-for-ui-to-be-updated-from-background-thread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!