How to Update a UILabel Object with MainActor

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?

My understanding is that you face the usual issue with drawing orders "stacked" in the main thread.

Somehow, they are not immediately drawn by the drawing engine, but it waits for all changes to be done to redraw. Hence only the las appears.

With DispatchQueue, each is handled independently.

As for the interest of MainActor, I found this really interesting to read.

https://www.swiftbysundell.com/articles/the-main-actor-attribute/

How to Update a UILabel Object with MainActor
 
 
Q