Giới thiệu
Trong phát triển iOS, thường cần thực thi một đoạn mã sau một khoảng thời gian trễ. Bài viết này giới thiệu 2 cách phổ biến: DispatchQueue.asyncAfter (khuyên dùng) và Timer.
Cách 1: DispatchQueue.asyncAfter (Khuyên dùng)
Sử dụng GCD (Grand Central Dispatch) - hiện đại, an toàn, dễ đọc.
Ví dụ trong Playground
func functionOne() {
let delayTime = DispatchTime.now() + 3.0 // 3 giây
print("Một")
DispatchQueue.main.asyncAfter(deadline: delayTime) {
hello()
}
}
func hello() {
print("Chào")
}
functionOne()
// Kết quả: "Một" in ra ngay, sau 3 giây in "Chào"
Trong dự án thực tế (ViewController)
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.performDelayedAction()
}
}
func performDelayedAction() {
print("Thực thi sau 2 giây")
// Cập nhật UI, gọi API, v.v.
}
Cách 2: Timer.scheduledTimer (Cách cũ)
Phù hợp khi cần lặp lại (repeating) hoặc cần hủy (invalidate) timer.
Ví dụ
class ViewController: UIViewController {
var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
print("Một")
timer = Timer.scheduledTimer(timeInterval: 3.0,
target: self,
selector: #selector(hello),
userInfo: nil,
repeats: false) // Chạy 1 lần
}
@objc func hello() {
print("Chào")
}
deinit {
timer?.invalidate() // Hủy timer khi view controller bị giải phóng
}
}
So sánh hai cách
| Đặc điểm | DispatchQueue.asyncAfter | Timer |
|---|---|---|
| Cú pháp | Closure-based, hiện đại | Target-Action, Objective-C style |
| Hủy thực thi | Khó (cần DispatchWorkItem) | Dễ dàng với timer.invalidate() |
| Lặp lại | Không hỗ trợ trực tiếp | Hỗ trợ repeats: true |
| Thread safety | Tốt (chỉ định queue) | Chạy trên RunLoop của thread tạo |
| Precision | Cao (nanosecond) | Thấp hơn (millisecond) |
Best Practice
- Ưu tiên
DispatchQueue.main.asyncAftercho các tác vụ đơn giản, chạy một lần. - Dùng
Timerkhi cần lặp lại hoặc cần khả năng hủy giữa chừng. - Luôn dùng
weak selftrong closure để tránh retain cycle:
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
self?.updateUI()
}