我明白所有的UI更新都必须在主线程上完成。
但是,为了更深入地了解GCD和dispatch main的工作原理:
我有一个按钮,运行一个网络调用,在它的completionHandler中最终执行以下操作:
为了使颜色更改发生,需要6-7秒钟。显然,如果从主线程运行上面的代码,它将立即更改边框颜色。
问题1: 即使我没有任何其他要运行的代码,为什么UI更改不会立即在后台线程中进行?等待了什么?
有趣的是,如果我点击按钮进行网络调用,然后在6-7秒内轻按文本输入框本身,边框颜色将立即更改。
这是因为:
我已经从后台线程更新了模型,即更改了文本字段的颜色,该操作排队更新UI/view...但由于我们处于后台队列中,UI更新可能需要几秒钟才能完成。
但是,我马上轻按了文本输入框,并迫使其快速读取文本输入框及其属性,包括边框——从主线程(实际用户触摸始终通过主线程处理)......即使尚未在屏幕上变为红色,但因为它在模型中是红色的,所以会从中读取并立即更改颜色为红色。
问题2: 这种观察是正确的吗?
如果我不轻按而只是等待: 如果我轻按: 完整代码如下:
但是,为了更深入地了解GCD和dispatch main的工作原理:
我有一个按钮,运行一个网络调用,在它的completionHandler中最终执行以下操作:
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
为了使颜色更改发生,需要6-7秒钟。显然,如果从主线程运行上面的代码,它将立即更改边框颜色。
问题1: 即使我没有任何其他要运行的代码,为什么UI更改不会立即在后台线程中进行?等待了什么?
有趣的是,如果我点击按钮进行网络调用,然后在6-7秒内轻按文本输入框本身,边框颜色将立即更改。
这是因为:
我已经从后台线程更新了模型,即更改了文本字段的颜色,该操作排队更新UI/view...但由于我们处于后台队列中,UI更新可能需要几秒钟才能完成。
但是,我马上轻按了文本输入框,并迫使其快速读取文本输入框及其属性,包括边框——从主线程(实际用户触摸始终通过主线程处理)......即使尚未在屏幕上变为红色,但因为它在模型中是红色的,所以会从中读取并立即更改颜色为红色。
问题2: 这种观察是正确的吗?
如果我不轻按而只是等待: 如果我轻按: 完整代码如下:
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()
}
}