# 12. Apple Native: Delegation Pattern va Retain Cycle Qotillari

> "Apple ekotizimida eng ko'p xotira oqishiga (Memory Leak) sabab bo'ladigan bitta so'z bor: u ham bo'lsa 'weak' so'zining unutilishidir. Delegation — bu Apple arxitekturasining yuragi, ammo ehtiyotsiz qo'llarda xotira qotilidir."

---

## 1. Delegation Pattern Nima va U Qanday Ishlaydi?

**Delegation (Vakillik)** — bu bir obyekt (Delegator) o'zida yuz bergan voqeani boshqa bir obyektga (Delegate) xabar qilish yoki biror qaror qabul qilishni unga topshirish imkonini beruvchi pattern.

```mermaid
sequenceDiagram
    autonumber
    participant VC as ProfileViewController (Delegate)
    participant View as CustomAvatarPickerView (Delegator)

    VC->>View: 1. view.delegate = self
    Note over View: Foydalanuvchi yangi rasm tanladi!
    View->>VC: 2. delegate?.avatarPicker(didSelect: image)
    VC-->>VC: 3. Rasmni serverga yuklash logikasini yurgizadi
```

### Apple'ning Mashhur Delegatlari:
* `UITableViewDelegate` — "Foydalanuvchi 4-qatorni bosdi, nima qilay?"
* `CLLocationManagerDelegate` — "Yangi GPS koordinata keldi, oling!"
* `WKNavigationDelegate` — "Veb sahifa ochilishni boshladi, ruxsat berasizmi?"

---

## 2. Retain Cycle Fojiasi: "weak" Nega Majburiy?

iOS da xotira **ARC (Automatic Reference Counting)** orqali boshqariladi. Obyektning Reference Count (kuchli havolalar soni) 0 ga teng bo'lgandagina u xotiradan (Heap) o'chiriladi.

```mermaid
flowchart LR
    subgraph Leak["❌ WEAK UNUTILSA: Retain Cycle (Xotira Oqishi)"]
        direction LR
        VC1["ViewController\n(Ref Count: 1)"] -->|"strong view"| V1["CustomView\n(Ref Count: 1)"]
        V1 -->|"strong delegate"| VC1
        Note1["💥 Ekranni yopganda ikkalasining ham\nRef Count'i 1 bo'lib qolaveradi!\ndeinit hech qachon chaqirilmaydi!"]
    end

    subgraph Fixed["✅ WEAK BILAN: Toza Xotira"]
        direction LR
        VC2["ViewController\n(Ref Count: 1)"] -->|"strong view"| V2["CustomView\n(Ref Count: 1)"]
        V2 -.->|"weak delegate (0 qo'shmaydi)"| VC2
        Note2["🚀 Ekran yopilganda ikkalasi ham\nxotiradan 100% o'chiriladi!"]
    end

    style Leak fill:#251014,stroke:#f87171,stroke-width:1px
    style Fixed fill:#0d1f14,stroke:#4ade80,stroke-width:1px
```

---

## 3. Real Swift 6 Kodi: Xavfsiz Delegat

```swift
import UIKit

// 1. Delegat Protokoli (Doimo ': AnyObject' bo'lishi shart, aks holda weak qo'yib bo'lmaydi!)
public protocol CustomInputViewDelegate: AnyObject, Sendable {
    func inputViewDidSubmit(text: String)
    func inputViewDidCancel()
}

// 2. Delegator (View)
public final class CustomInputView: UIView {
    // ⚠️ ENG MUHIM SO'Z: 'weak'
    public weak var delegate: (any CustomInputViewDelegate)?
    
    public func submitTapped(text: String) {
        delegate?.inputViewDidSubmit(text: text)
    }
    
    public func cancelTapped() {
        delegate?.inputViewDidCancel()
    }
    
    deinit {
        print("🗑 CustomInputView xotiradan muvaffaqiyatli o'chirildi!")
    }
}

// 3. Delegate (ViewController)
public final class RegistrationViewController: UIViewController, CustomInputViewDelegate {
    private let inputView = CustomInputView()
    
    public override func viewDidLoad() {
        super.viewDidLoad()
        // O'zimizni delegat qilib tayinlaymiz
        inputView.delegate = self
        view.addSubview(inputView)
    }
    
    public func inputViewDidSubmit(text: String) {
        print("Kiritilgan matn: \(text)")
    }
    
    public func inputViewDidCancel() {
        dismiss(animated: true)
    }
    
    deinit {
        print("🗑 RegistrationViewController xotiradan muvaffaqiyatli o'chirildi! (No Leak)")
    }
}
```

---

## 4. Retain Cycle'ni Xcode da Qanday Aniqlash Mumkin?

Senior dasturchi har bir yangi ekranni yozgach, uni xotirada qolib ketmaganini tekshiradi:
1. **`deinit` tekshiruvi:** Har bir ViewController'ga `deinit { print("🗑 Deallocated") }` yozib ko'ring. Ekranni yopganingizda ushbu log chiqmasa — demak Retain Cycle bor!
2. **Xcode Memory Graph Debugger:** Xcode'ning pastki panelidagi 3 ta doiracha belgisini bosing. Agar ViewController ustida qizil belgi turgan bo'lsa va u hali ham xotirada yashayotgan bo'lsa, havolalar zanjirini grafikda ko'rsatadi.

---

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

<details>
<summary><b>1-Savol: Nega Swift'da faqat 'AnyObject' (Class) ga cheklangan protokollargagina 'weak' qo'yish mumkin?</b> (Yechimni ko'rish uchun bosing)</summary>

**Tahlil va Yechim:**
Chunki `weak` faqat Reference Type (Class) lar uchun ishlaydi — ARC xotira hisoblagichiga murojaat qiladi. Struct va Enum lar esa Value Type bo'lib, ular Heap'da emas, Stack'da saqlanadi va ularda Reference Counting bo'lmaydi. Shuning uchun `protocol MyDelegate: AnyObject` deb yozilmasa, Swift kompilyatori `weak cannot be applied to non-class-bound protocol` xatosini beradi.
</details>

<details>
<summary><b>2-Savol: Delegation va Closure (Callback) o'rtasida qachon qaysi birini tanlash kerak?</b> (Yechimni ko'rish uchun bosing)</summary>

**Tahlil va Yechim:**
* **Closure:** Agar faqat 1 ta oddiy hodisa (masalan, tugma bosildi yoki ma'lumot keldi) bo'lsa, Closure yozish oson va qisqa.
* **Delegation:** Agar voqealar soni 3 tadan ko'p bo'lsa (masalan: boshlandi, xato bo'ldi, tugadi, progress o'zgardi, ruxsat so'raldi), Delegation tanlanadi. U barcha metodlarni bitta tartibli protokolga jamlaydi.
</details>

---

## 6. Amaliy Topshiriq (Senior Challenge)

`AudioRecorderService` sinfini yarating:
* Uning `AudioRecorderDelegate` nomli protokoli bo'lsin: `didStartRecording()`, `didUpdateVolumeLevel(dB: Float)`, `didFinishRecording(url: URL)`.
* Ushbu xizmatni ViewModel bilan zaif havola (`weak delegate`) orqali bog'lang va konsolda `deinit` chaqirilishini tekshiring!
