Skip to Content
Swift📘 Ngôn ngữ SwiftMemory Management (ARC)

Memory Management (ARC) trong Swift

1. Giới thiệu

Swift sử dụng Automatic Reference Counting (ARC) để quản lý bộ nhớ tự động.

2. Reference Counting hoạt động

class Person { let name: String init(name: String) { self.name = name print("\(name) được khởi tạo") } deinit { print("\(name) bị hủy") } } // Reference count = 1 var person1: Person? = Person(name: "John") // Reference count = 2 var person2 = person1 // Reference count = 1 person1 = nil // Reference count = 0 → deinit được gọi person2 = nil // Output: John bị hủy

3. Strong Reference Cycles (Vấn đề)

class Person { let name: String var apartment: Apartment? init(name: String) { self.name = name } deinit { print("\(name) deinit") } } class Apartment { let number: Int var tenant: Person? // ⚠️ Strong reference init(number: Int) { self.number = number } deinit { print("Apartment \(number) deinit") } } var john: Person? = Person(name: "John") var apt: Apartment? = Apartment(number: 101) // Tạo cycle john?.apartment = apt apt?.tenant = john // Memory leak! deinit không được gọi john = nil apt = nil

4. Weak References

class Person { let name: String var apartment: Apartment? init(name: String) { self.name = name } deinit { print("\(name) deinit") } } class Apartment { let number: Int weak var tenant: Person? // ✅ Weak reference init(number: Int) { self.number = number } deinit { print("Apartment \(number) deinit") } } var john: Person? = Person(name: "John") var apt: Apartment? = Apartment(number: 101) john?.apartment = apt apt?.tenant = john // Bây giờ deinit được gọi đúng john = nil // "John deinit" apt = nil // "Apartment 101 deinit"

5. Unowned References

class Customer { let name: String var card: CreditCard? init(name: String) { self.name = name } deinit { print("\(name) deinit") } } class CreditCard { let number: String unowned let customer: Customer // Luôn có customer init(number: String, customer: Customer) { self.number = number self.customer = customer } deinit { print("Card \(number) deinit") } } var john: Customer? = Customer(name: "John") john?.card = CreditCard(number: "1234", customer: john!) john = nil // John deinit // Card 1234 deinit

6. Weak vs Unowned

WeakUnowned
OptionalCó (?)Không
Khi nilTự động = nilCrash nếu truy cập
Dùng khiReference có thể nilReference luôn tồn tại
// Weak: delegate có thể nil class TableView { weak var delegate: TableViewDelegate? } // Unowned: child luôn có parent class Child { unowned let parent: Parent }

7. Closures và Capture Lists

class ViewController { var name = "Main" func setupHandler() { // ⚠️ Strong capture tạo cycle let handler = { print(self.name) } // ✅ Weak capture let safeHandler = { [weak self] in guard let self = self else { return } print(self.name) } // ✅ Unowned capture let unownedHandler = { [unowned self] in print(self.name) } } }

8. Capture List với Multiple Values

class DataLoader { var data: [String] = [] func load() { let url = URL(string: "https://api.com")! URLSession.shared.dataTask(with: url) { [weak self, url] data, _, _ in // url được capture by value print("Loaded from: \(url)") // self được capture weakly self?.data = ["loaded"] } } }

9. Common Patterns

// Pattern 1: Completion handlers class NetworkManager { func fetchData(completion: @escaping (Data) -> Void) { // ... } } class ViewModel { let network = NetworkManager() var data: Data? func load() { network.fetchData { [weak self] data in self?.data = data } } } // Pattern 2: Delegate pattern protocol DownloadDelegate: AnyObject { func didFinish() } class Downloader { weak var delegate: DownloadDelegate? } // Pattern 3: Timer class TimerController { var timer: Timer? func start() { timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in self?.tick() } } func tick() { print("Tick") } deinit { timer?.invalidate() } }

10. Debug Memory Issues

// Sử dụng deinit để debug class DebugObject { let id: String init(id: String) { self.id = id print("🟢 Created: \(id)") } deinit { print("🔴 Destroyed: \(id)") } } // Xcode Instruments: Leaks & Allocations // Debug Memory Graph trong Xcode

📝 Tóm tắt

  • ARC tự động đếm references và giải phóng bộ nhớ
  • Strong reference cycles gây memory leak
  • weak - optional, có thể nil
  • unowned - non-optional, crash nếu accessed khi nil
  • Closures: dùng [weak self] hoặc [unowned self]
  • Delegates nên là weak
Last updated on