I guess I was in coma, and I didn't learn of MainActor till today.
So I have the following lines of code to test MainActor.
import UIKit
class ViewController: UIViewController {
// MARK: - IBOutlet
@IBOutlet weak var label: UILabel!
// MARK: - IBAction
@IBAction func buttonTapped(_ sender: UIButton) {
Task {
do {
let bool = try await asyncWaitMakeLabelChanges()
if bool {
print("I'm done!")
}
} catch {
print("\(error.localizedDescription)")
}
}
}
func asyncWaitMakeLabelChanges() async throws -> Bool {
for i in 0..<5 {
let text = String(i)
label.text = text // UILabel.text must be used from main thread only
print(text)
sleep(1)
}
return true
}
}
As I expect, I get the purple main thread checker error at the line where I update the label. That's good. And I've changed the code as follows.
import UIKit
class ViewController: UIViewController {
// MARK: - IBOutlet
@IBOutlet weak var label: UILabel!
// MARK: - IBAction
@IBAction func buttonTapped(_ sender: UIButton) {
Task {
do {
let bool = try await asyncWaitMakeLabelChanges()
if bool {
print("I'm done!")
}
} catch {
print("\(error.localizedDescription)")
}
}
}
func asyncWaitMakeLabelChanges() async throws -> Bool {
for i in 0..<5 {
let text = String(i)
Task { @MainActor in
label.text = text
}
print(text)
sleep(1)
}
return true
}
}
Okay. The app won't crash. But the label won't get updated every second. It will finally display the number (4) when the count reaches 4. So my question is why not?
I could change my code as follows to update my label every second.
func asyncWaitMakeLabelChanges() async throws -> Bool {
for i in 0..<5 {
let text = String(i)
DispatchQueue.main.async() { [weak self] in
self?.label.text = text
}
print(text)
sleep(1)
}
return true
}
So why would I want to use MainActor?