# 08. Behavioral: Observer Pattern — Reaktiv Dasturlash Asosi

> "Agar siz ma'lumot yangilanganini bilish uchun har 1 soniyada taymer bilan tekshirib (Polling) tursangiz — bu batareyani o'ldirishdir. Observer patterni ma'lumot o'zgargandagina barcha qiziquvchilarni avtomatik uyg'otadi (Push Notification modeli)."

---

## 1. Observer Pattern Nima va Uning Apple Ekotizimidagi Evolyutsiyasi

**Observer (Kuzatuvchi)** — bu bitta obyektning (Subject/Publisher) holati o'zgarganda, unga obuna bo'lgan barcha boshqa obyektlarga (Observers/Subscribers) bu haqda avtomatik xabar beruvchi xulq-atvor andozasidir.

```mermaid
flowchart TD
    Subject["Subject (Masalan: CartManager / Savat)\nBalans yoki mahsulotlar o'zgardi!"]
    
    Subject -->|"notifyObservers()"| Obs1["Observer 1: CartBadgeView\n(Qizil doiradagi sonni yangilaydi)"]
    Subject -->|"notifyObservers()"| Obs2["Observer 2: CheckoutSummaryView\n(Jami summani qayta hisoblaydi)"]
    Subject -->|"notifyObservers()"| Obs3["Observer 3: AnalyticsTracker\n('cart_updated' eventini yuboradi)"]

    style Subject fill:#131720,stroke:#bef264,stroke-width:2px
    style Obs1 fill:#181d26,stroke:#7da2ce,stroke-width:1px
    style Obs2 fill:#181d26,stroke:#7da2ce,stroke-width:1px
    style Obs3 fill:#181d26,stroke:#7da2ce,stroke-width:1px
```

### Apple Ekotizimida Observerning 4 Avlodi:
1. **1-Avlod (Objective-C):** `NSNotificationCenter` va `KVO (Key-Value Observing)`. String kalitlar xavfli va har safar `removeObserver()` chaqirish esdan chiqsa crash bo'lardi.
2. **2-Avlod (RxSwift):** Uchinchi tomon reaktiv kutubxonalari.
3. **3-Avlod (iOS 13+):** `Combine` freymvorki (`@Published`, `CurrentValueSubject`, `PassthroughSubject`).
4. **4-Avlod (Swift 5.9+ / Swift 6):** Sof `@Observable` makrosi va `AsyncSequence` / `AsyncStream`.

---

## 2. Noldan O'zimizning Thread-Safe Observer Tizimimizni Qurish

Keling, hech qanday tashqi freymvorklarsiz sof Swift 6 da xotira oqishidan (Memory Leak) xoli Observer quramiz:

### Retain Cycle Xavfi va Zaif Havola (Weak Wrapper):
Agar Subject kuzatuvchilarni oddiy massivda (`[Observer]`) saqlasa, u ularni kuchli (strong) ushlab turadi. Natijada obunachi ViewController yopilsa ham xotiradan o'chmay qoladi.
**Yechim:** `WeakObserverBox` konteyneri:

```swift
import Foundation

// 1. Kuzatuvchi Protokoli
public protocol CartObserver: AnyObject, Sendable {
    func cartDidUpdate(totalItems: Int, totalPrice: Double)
}

// 2. Weak Wrapper (Xotira oqishini oldini oladi)
final class WeakObserverBox: @unchecked Sendable {
    weak var value: (any CartObserver)?
    init(_ value: any CartObserver) {
        self.value = value
    }
}

// 3. Markaziy Subject
public final class CartManager: @unchecked Sendable {
    public static let shared = CartManager()
    
    private let lock = NSLock()
    private var observers: [WeakObserverBox] = []
    
    private(set) var itemsCount: Int = 0
    private(set) var totalAmount: Double = 0.0
    
    private init() {}
    
    public func addObserver(_ observer: any CartObserver) {
        lock.lock()
        defer { lock.unlock() }
        // Avval o'lgan (nil bo'lgan) kuzatuvchilarni tozalaymiz
        observers.removeAll { $0.value == nil }
        observers.append(WeakObserverBox(observer))
    }
    
    public func addItem(price: Double) {
        lock.lock()
        itemsCount += 1
        totalAmount += price
        let currentCount = itemsCount
        let currentTotal = totalAmount
        // O'lik havolalarni tozalash
        observers.removeAll { $0.value == nil }
        let validObservers = observers.compactMap { $0.value }
        lock.unlock()
        
        // Barcha obunachilarni xabardor qilish
        for observer in validObservers {
            observer.cartDidUpdate(totalItems: currentCount, totalPrice: currentTotal)
        }
    }
}
```

---

## 3. Zamonaviy Swift 6 Standarti: @Observable va AsyncStream

Swift 6 da endi eski delegate yoki Combine o'rniga toza til xususiyatlari qo'llaniladi:

### 1. SwiftUI uchun `@Observable`:
```swift
import SwiftUI

@Observable
public final class StockTicker {
    public var applePrice: Double = 220.50
    public var googlePrice: Double = 175.20
    
    public func updatePrices(apple: Double, google: Double) {
        self.applePrice = apple
        self.googlePrice = google
    }
}
```
SwiftUI ko'rinishida faqat o'sha o'zgaruvchi ishlatilgan joylar avtomatik re-render bo'ladi!

### 2. Fon Oqimlari uchun `AsyncStream`:
```swift
public final class LocationTracker {
    public func locationStream() -> AsyncStream<String> {
        AsyncStream { continuation in
            // GPS yangilanganda
            continuation.yield("41.31, 69.24")
            
            continuation.onTermination = { _ in
                // GPS to'xtatildi
            }
        }
    }
}

// Qabul qiluvchi tomonda:
Task {
    for await coordinate in tracker.locationStream() {
        print("Yangi nuqta: \(coordinate)")
    }
}
```

---

## 4. Retain Cycle Qopqoni: [weak self] Nega Majburiy?

Combine yoki qadimiy NotificationCenter ishlatganda quyidagi xatoga yo'l qo'ymang:

```swift
// ❌ FOJIALI RETAIN CYCLE:
cancellable = cartService.$total
    .sink { newTotal in
        self.updateLabel(newTotal) // self kuchli ushlab qolindi!
    }

// ✅ TO'G'RI: [weak self]
cancellable = cartService.$total
    .sink { [weak self] newTotal in
        self?.updateLabel(newTotal)
    }
```

---

## 5. Interaktiv Savol-Javob (Self-Check Quiz)

<details>
<summary><b>1-Savol: Observer pattern va Pub/Sub (Publish-Subscribe) arxitekturasi o'rtasida qanday nozik farq bor?</b> (Yechimni ko'rish uchun bosing)</summary>

**Tahlil va Yechim:**
* **Observer patternida** Subject obunachilar ro'yxatini to'g'ridan-to'g'ri o'zi biladi va ularning interfeys metodini chaqiradi.
* **Pub/Sub arxitekturasida** (masalan, `NotificationCenter` yoki Redis Event Bus) Publisher va Subscriber bir-birini mutlaqo bilmaydi! Ularning o'rtasida mustaqil **Message Broker / Event Channel** turadi.
</details>

<details>
<summary><b>2-Savol: Nega Swift 6 da '@Observable' makrosi Combine'dagi 'ObservableObject'dan 10x samaraliroq?</b> (Yechimni ko'rish uchun bosing)</summary>

**Tahlil va Yechim:**
Combine'dagi `ObservableObject` da birorta `@Published` maydon o'zgarsa, `objectWillChange` orqali **butun View** qayta chizilardi (keraksiz renderlar). Yangi `@Observable` makrosi esa View ichida aynan qaysi bitta xususiyat o'qilgan bo'lsa (Fine-Grained Tracking), faqat o'sha yozuvnigina yangilaydi.
</details>

---

## 6. Amaliy Topshiriq (Senior Challenge)

`UserSessionSubject` sinfini yarating:
* Foydalanuvchi tizimga kirganida (`login`), chiqqanida (`logout`) va token yangilanganda barcha ro'yxatdan o'tgan kuzatuvchilarni xabardor qilsin.
* Har bir obunachining xotiradan to'g'ri o'chirilishini (`Weak Reference`) Unit Test orqali tasdiqlang!
