Memory Management (ARC)
1. Giới thiệu
Phần tiêu đề “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
Phần tiêu đề “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 = 1var person1: Person? = Person(name: "John")
// Reference count = 2var person2 = person1
// Reference count = 1person1 = nil
// Reference count = 0 → deinit được gọiperson2 = nil// Output: John bị hủy3. Strong Reference Cycles (Vấn đề)
Phần tiêu đề “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 cyclejohn?.apartment = aptapt?.tenant = john
// Memory leak! deinit không được gọijohn = nilapt = nil4. Weak References
Phần tiêu đề “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 = aptapt?.tenant = john
// Bây giờ deinit được gọi đúngjohn = nil // "John deinit"apt = nil // "Apartment 101 deinit"5. Unowned References
Phần tiêu đề “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 deinit6. Weak vs Unowned
Phần tiêu đề “6. Weak vs Unowned”| Weak | Unowned | |
|---|---|---|
| Optional | Có (?) |
Không |
| Khi nil | Tự động = nil | Crash nếu truy cập |
| Dùng khi | Reference có thể nil | Reference luôn tồn tại |
// Weak: delegate có thể nilclass TableView { weak var delegate: TableViewDelegate?}
// Unowned: child luôn có parentclass Child { unowned let parent: Parent}7. Closures và Capture Lists
Phần tiêu đề “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
Phần tiêu đề “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
Phần tiêu đề “9. Common Patterns”// Pattern 1: Completion handlersclass 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 patternprotocol DownloadDelegate: AnyObject { func didFinish()}
class Downloader { weak var delegate: DownloadDelegate?}
// Pattern 3: Timerclass 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
Phần tiêu đề “10. Debug Memory Issues”// Sử dụng deinit để debugclass 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
Phần tiêu đề “📝 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ể nilunowned- non-optional, crash nếu accessed khi nil- Closures: dùng
[weak self]hoặc[unowned self] - Delegates nên là
weak