# UIKit 4: Xotira boshqaruvi va ARC — Retain Cycle, CoW va Instruments

> **Holat:** 2026-yil sentabr. iOS ilovalarda xotira sizib chiqishi (memory leak) nafaqat ilova tezligini pasaytiradi, balki tizim tomonidan ilovaning majburiy o'ldirilishiga (OOM — Out of Memory Crash) olib keladi. Ushbu darsda ARC qoidalari, real simulyator testlarida o'lchangan 4 ta asosiy Retain Cycle holati, Copy-on-Write (CoW) arxitekturasi va autoreleasepool qo'llanilishi amaliy misollarda ko'rsatiladi.

## Mundarija

1. [ARC mexanizmi: Strong, Weak va Unowned](#arc-basics)
2. [O'lchangan faktlar: Klojurlar va [weak self]](#closures)
3. [Delegatlar: strong delegate xatosi](#delegates)
4. [Timer va NotificationCenter xotira tuzoqlari](#timer-notifications)
5. [Copy-on-Write (CoW) qanday ishlaydi?](#cow)
6. [Autoreleasepool: xotira cho'qqilarini (spikes) yo'qotish](#autoreleasepool)
7. [Xotira oqishini topish: Memory Graph va Instruments](#diagnostics)
8. [Xulosa](#xulosa)
9. [Manbalar](#manbalar)

---

## 1. ARC mexanizmi: Strong, Weak va Unowned {#arc-basics}

Swift'da xotira boshqaruvi **ARC (Automatic Reference Counting)** tomonidan amalga oshiriladi: ob'ektga bo'lgan kuchli havolalar soni 0 ga tushganda, u xotiradan o'chiriladi (`deinit`).

| Havola turi | Xotira xatti-harakati | Qachon ishlatiladi |
| :--- | :--- | :--- |
| **`strong`** | Hisoblagichni 1 ga oshiradi | Ob'ektga egalik qilganda (sukut bo'yicha) |
| **`weak`** | Hisoblagichni oshirmaydi; ob'ekt o'chganda avtomatik `nil` bo'ladi | Delegatlar, klojurlar, doimo ixtiyoriy (`Optional`) bo'ladi |
| **`unowned`** | Hisoblagichni oshirmaydi; ob'ekt o'chganda `nil` bo'lmaydi | Ikki ob'ekt bir vaqtda yashab, bir vaqtda o'lishiga 100% ishonch bo'lganda |

> **Ogohlantirish:** Agar ob'ekt xotiradan o'chib ketgandan keyin unga `unowned` orqali murojaat qilinsa, ilova darhol qulaydi:  
> `Fatal error: Attempted to read an unowned reference but the object was already deallocated`.

---

## 2. O'lchangan faktlar: Klojurlar va [weak self] {#closures}

iOS 26.5 simulyatorida XCTest orqali o'tkazilgan eksperiment natijalari ([executed_facts.md](file:///Users/codingtech/Documents/GitHub/azimjondev.uz/lessons-handoff/research-uikit/executed_facts.md)):

```swift
import Foundation

final class DataService {
  var onCompletion: (() -> Void)?
}

final class StrongOwner {
  let service = DataService()
  init() {
    // XATO: self kuchli ushlab qolinadi:
    service.onCompletion = { self.updateUI() }
  }
  func updateUI() {}
}

final class WeakOwner {
  let service = DataService()
  init() {
    // TO'G'RI: [weak self] siklni buzadi:
    service.onCompletion = { [weak self] in self?.updateUI() }
  }
  func updateUI() {}
}
```

O'lchov natijasi:
- `closure captures self strongly -> owner freed after scope: false` (Xotirada abadiy qolib ketadi!).
- `closure captures [weak self] -> owner freed after scope: true` (Xotiradan to'g'ri bo'shatiladi).

---

## 3. Delegatlar: strong delegate xatosi {#delegates}

Delegat xususiyatini e'lon qilishda eng ko'p uchraydigan xato — `weak` so'zini unutishdir:

```swift
import Foundation

// 1. Protokol AnyObject'dan meros olishi shart:
public protocol PaymentViewDelegate: AnyObject {
  func paymentDidComplete()
}

public final class PaymentView {
  // TO'G'RI: weak bo'lishi shart!
  public weak var delegate: PaymentViewDelegate?

  public init() {}
}
```

O'lchangan fakt:
- Agar delegat `strong` bo'lsa -> `screen freed: false` (View Controller ekrandan ketsa ham xotirada qoladi).
- Agar delegat `weak` bo'lsa -> `screen freed: true`.

---

## 4. Timer va NotificationCenter xotira tuzoqlari {#timer-notifications}

### 1. Timer tuzog'i
Klassik `Timer.scheduledTimer(timeInterval:target:selector:...)` o'zining `target` parametrini Run Loop ichida **kuchli (strong)** ushlab turadi.

O'lchangan fakt:
- Timer ishlayotgan paytda controller bo'shatilmaydi (`owner freed: false`).
- Faqat `timer.invalidate()` chaqirilgandagina ob'ekt xotiradan bo'shatiladi (`after timer.invalidate() -> owner freed: true`)!

Zamonaviy va xavfsiz blokli Timer:

```swift
import Foundation

public final class PollingManager {
  private var timer: Timer?

  public func start() {
    // [weak self] bilan blokli Timer Run Loop siklini oldini oladi:
    timer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { [weak self] _ in
      self?.pingServer()
    }
  }

  public func stop() {
    timer?.invalidate()
    timer = nil
  }

  private func pingServer() {}

  deinit {
    timer?.invalidate()
  }
}
```

### 2. NotificationCenter tuzog'i
- **Selector-based:** `NotificationCenter.default.addObserver(self, selector: ...)` iOS 9 dan boshlab zeroing-weak reference ishlatadi, shuning uchun `deinit`da `removeObserver` qilmasa ham retain cycle bo'lmaydi (`observer freed: true`).
- **Block-based:** `addObserver(forName:queue:using:)` esa o'z ichida `self`ni kuchli ushlab qolsa, **retain cycle hosil qiladi (`observer freed: false`)**! Buning oldini olish uchun token saqlanishi va `deinit` da olib tashlanishi shart.

---

## 5. Copy-on-Write (CoW) qanday ishlaydi? {#cow}

Swift'dagi massivlar (`Array`), lug'atlar (`Dictionary`) va qatorlar (`String`) qiymatli turlar (struct) hisoblanadi. Biroq har safar massiv boshqa o'zgaruvchiga berilganda xotira darhol nusxalanmaydi.

O'lchangan ilmiy natija:

```swift
import Foundation

func testCopyOnWrite() {
  var a = Array(0..<1000)
  let b = a

  // 1. Mutatsiyadan oldin a va b bitta xotira manziliga qaraydi:
  // Array copy shares storage before mutation: true

  a[0] = 99

  // 2. Yozish (mutatsiya) sodir bo'lgan paytda a uchun alohida nusxa ochiladi:
  // after mutating one copy still shared: false; b[0] = 0
}
```

Bu **Copy-on-Write** deb ataladi. U xotirani vaqtinchalik nusxalashdan asraydi va faqat o'zgarish kiritilgan nusxa uchun yangi RAM ajratadi.

---

## 6. Autoreleasepool: xotira cho'qqilarini (spikes) yo'qotish {#autoreleasepool}

Katta hajmdagi sikllarda (masalan, 1,000 ta rasmni qayta ishlash) vaqtinchalik yaratilgan CoreGraphics yoki Objective-C ob'ektlari Run Loop tugamaguncha xotirada to'planib qoladi. Natijada xotira birdan $500\text{ MB}$ ga sakrab, ilova qulaydi.

Buning yechimi — **`autoreleasepool`**:

```swift
import Foundation

func processBatchImages(urls: [URL]) {
  for url in urls {
    autoreleasepool {
      // Har bir aylanmada hosil bo'lgan vaqtinchalik xotira
      // blok yakunlanishi bilan darhol tozalanadi:
      let _ = try? Data(contentsOf: url)
    }
  }
}
```

---

## 7. Xotira oqishini topish: Memory Graph va Instruments {#diagnostics}

Retain cycle'larni topishning 3 ta asosiy yo'li:

1. **`deinit` ichida log qo'yish:** Har bir controller va servisda `deinit { print("\(Self.self) bo'shatildi") }` bo'lishi kerak. Agar ekrandan chiqqanda bu yozuv chiqmasa — retain cycle bor.
2. **Xcode Memory Graph Debugger:** Pastki panelda 3 ta doiracha belgisi. U ob'ektlar o'rtasidagi kuchli havolalar zanjirini vizual ko'rsatadi va shubhali sikllarni binafsha rangli ogohlantirish bilan belgilaydi.
3. **Instruments (Leaks & Allocations):** Ilovani profayl qilish uchun eng kuchli vosita bo'lib, xotira hajmining o'sish dinamikasini real vaqt rejimida qayd etadi.

---

## 8. Xulosa {#xulosa}

- Retain cycle ikkita ob'ekt bir-birini kuchli (strong) ushlab turganda yuzaga keladi.
- Klojurlarda `[weak self]` ishlatish va delegatlarni `weak` qilish xotira xavfsizligining oltin qoidasidir.
- `unowned` faqat ikkinchi ob'ekt birinchisidan oldin hech qachon o'chmasligiga 100% kafolat bo'lganda qo'llanilishi kerak, aks holda crash beradi.
- Blokli NotificationCenter va Target-Action Timer doimo qo'lda bekor qilinishi (`invalidate` / `removeObserver`) shart.
- Swift CoW orqali faqat ma'lumot o'zgargandagina yangi xotira ajratadi.
- Sikllardagi xotira cho'qqilarini yo'qotish uchun `autoreleasepool` dan foydalaniladi.

---

## Manbalar {#manbalar}

1. [Automatic Reference Counting — Swift Language Guide](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/automaticreferencecounting/)
2. [Finding Memory Leaks with Instruments — Apple Developer](https://developer.apple.com/documentation/xcode/diagnosing-memory-performance-issues)
3. [Timer.scheduledTimer Documentation — Apple](https://developer.apple.com/documentation/foundation/timer/1412416-scheduledtimer)
4. [Using Autorelease Pool Blocks — Apple Archive](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html)
