Một closure capture (bắt giữ) các biến nó tham chiếu, giữ chúng sống. Khi closure capture self mà self cũng giữ closure đó (là stored property), chúng giữ nhau sống mãi mãi — một làm rò bộ nhớ. Một như sẽ phá vòng đó.
Một closure capture (bắt giữ) các biến nó tham chiếu, giữ chúng sống. Khi closure capture self mà self cũng giữ closure đó (là stored property), chúng giữ nhau sống mãi mãi — một làm rò bộ nhớ. Một như sẽ phá vòng đó.
[weak self]ARC giải phóng một object khi reference count của nó về 0. Một capture kiểu strong sẽ tăng con số đó.
final class Downloader {
var onDone: (() -> Void)? // closure lưu trữ -> strong
func start() {
// TỆ: closure capture self kiểu strong, self giữ closure -> cycle
onDone = { self.cleanup() }
// TỐT: capture kiểu weak, self có thể deallocate
onDone = { [weak self] in
guard let self else { return } // unwrap an toàn; thoát nếu đã mất
self.cleanup()
}
}
func cleanup() {}
}
[weak self] — self trở thành optional; là nil nếu object đã bị giải phóng. Mặc định an toàn khi object có thể sống lâu hơn closure.[unowned self] — non-optional, không tốn ARC, nhưng crash nếu self đã mất. Chỉ dùng khi chắc chắn self sống lâu hơn closure.Task { [weak self] in
let data = await self?.fetch() // self? ngắn mạch nếu đã deallocate
}
Closure không-escaping (vd. map, filter, forEach) chạy đồng bộ và nhả capture ngay — không cycle, không cần [weak self]. Rủi ro nằm ở closure escaping và được lưu trữ: completion handler, Timer, NotificationCenter, Combine sink, delegate block.
Retain cycle là kiểu rò bộ nhớ phổ biến nhất trên iOS, và chúng vô hình cho tới khi Instruments cho thấy bộ nhớ tăng dần. Biết chính xác khi nào closure escaping và vì sao cần [weak self] — thay vì rải nó khắp nơi theo phản xạ — phân biệt kỹ sư hiểu ARC với người chỉ làm theo thói quen.
Thư viện câu hỏi phỏng vấn IT với đáp án chi tiết — từ Junior đến Senior.
Ủng hộ