# 08. Performance, Caching va 120 FPS ProMotion: Zero-Jank Arxitekturasi

> "Foydalanuvchi ilovangiz SDUI ekanini bilmasligi kerak. Agar sahifani aylantirganda (scroll) mikro-qotish (jank) sezilsa yoki ekranni ochish 1 soniyadan ortiq vaqt olsa — arxitekturangiz yutqazdi."

---

## 1. Zero-Jank Qoidasi: ProMotion 8.33 ms Kadr Byudjeti

iPhone 13 Pro va undan keyingi barcha zamonaviy Apple qurilmalarida ekran yangilanish chastotasi **120 Hz (ProMotion)** ni tashkil etadi. Bu har bir kadr ekranga chizilishi uchun protsessorga bor-yo'g'i **8.33 millisekund** vaqt berilishini anglatadi:

$$\text{Frame Budget} = \frac{1000\text{ ms}}{120\text{ fps}} \approx 8.33\text{ ms}$$

Agar siz 60 KB lik SDUI JSON faylini `Main Thread` (asosiy oqim)da pars qilsangiz:
* `JSONDecoder().decode(...)` o'rtacha **18–25 ms** vaqt oladi.
* Natijada 2-3 ta kadr tashlab ketiladi (Dropped Frames).
* Foydalanuvchi barmoq bilan sahifani yurgizganda qotish (Jank/Stutter) yuz beradi!

```mermaid
flowchart TD
    subgraph BadThread["❌ Asosiy Oqimda (Main Thread) Parslash"]
        direction TB
        M1["Main Thread (UI + Touch + Render)"]
        M1 -->|"JSONDecoder.decode() ishga tushdi (22 ms)"| Frozen["⚠️ MAIN THREAD 22 ms GA MUZLADI!\n2 ta kadr yo'qoldi (Dropped Frames)\nFoydalanuvchi ekranning qotganini ko'radi!"]
    end

    subgraph GoodThread["✅ Swift 6 Background Actor Bilan"]
        direction TB
        Main["Main Thread: 120 FPS Silliq UI"]
        Actor["Background DataEngine Actor"]
        
        Main -.->|"URL request jo'natildi"| Actor
        Actor -->|"Fonda parslash va autorelease (20 ms)"| Actor
        Actor -->|"Tayyor [ComponentNode] yuborildi"| Main
        Main -->|"0.05 ms: Faqat View yangilandi"| Smooth["🚀 120 FPS Silliq Scrolling!"]
    end

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

---

## 2. Swift 6 Background Actor bilan Parallallashtirish

JSON'ni tarmoqdan yuklab olish va Swift modellariga o'g'irish 100% fon oqimida (Background Actor) bajarilishi shart:

```swift
import Foundation

/// Swift 6 Concurrency asosidagi xavfsiz fon aktori
public actor SDUIDataEngine {
    public static let shared = SDUIDataEngine()
    private let decoder: JSONDecoder
    
    public init() {
        self.decoder = JSONDecoder()
    }
    
    /// To'liq background thread'da parslash
    public func parseScreen(from data: Data) throws -> SDUIScreenPayload {
        // Fon oqimida vaqtinchalik xotirani darhol tozalash uchun autoreleasepool
        try autoreleasepool {
            try decoder.decode(SDUIScreenPayload.self, from: data)
        }
    }
}
```

UI qatlamida esa faqat tayyor modellar `@MainActor` ga uzatiladi:

```swift
@MainActor
public func loadScreen(from url: URL) async {
    do {
        let (data, response) = try await URLSession.shared.data(from: url)
        
        // 1. Fon oqimida parslash (Main thread ozod!)
        let parsedScreen = try await SDUIDataEngine.shared.parseScreen(from: data)
        
        // 2. Asosiy oqimda faqat View'ni yangilash (0.05 ms)
        self.components = parsedScreen.components
    } catch {
        self.handleError(error)
    }
}
```

---

## 3. Stale-While-Revalidate (SWR) Kesh Strategiyasi

Foydalanuvchi metroda yoki internet sust joyda ilovani ochganda bo'sh oq ekran ko'rmasligi kerak:

```mermaid
sequenceDiagram
    autonumber
    participant User as Foydalanuvchi
    participant UI as SwiftUI View
    participant Cache as SDUICacheManager (Disk)
    participant Server as Backend API

    User->>UI: Ilovani ochadi
    UI->>Cache: Oxirgi snapshot bormi?
    Cache-->>UI: Ha! (data, eTag: "v2.4")
    UI-->>User: 0 ms: Ekranni darhol keshdan chizadi (Instant Launch!)
    
    UI->>Server: Orqa fonda: GET /screen (If-None-Match: "v2.4")
    alt Ma'lumot o'zgarmagan bo'lsa
        Server-->>UI: 304 Not Modified (0 bayt data!)
    else Yangi o'zgarish bo'lsa
        Server-->>UI: 200 OK + Yangi JSON
        UI->>Cache: Yangi snapshotni diskka yozish
        UI->>UI: Faqat o'zgargan qismlarni animatsiya bilan yangilash
        UI-->>User: Yangilangan UI ko'rinadi
    end
```

---

## 4. Swift 6 Kesh Boshqaruvchisi Kodi

```swift
import Foundation

public final class SDUICacheManager: Sendable {
    public static let shared = SDUICacheManager()
    private let fileManager = FileManager.default
    private let cacheDirectory: URL
    
    private init() {
        let paths = fileManager.urls(for: .cachesDirectory, in: .userDomainMask)
        self.cacheDirectory = paths[0].appendingPathComponent("SDUISnapshots")
        try? fileManager.createDirectory(at: cacheDirectory, withIntermediateDirectories: true)
    }
    
    public func saveSnapshot(data: Data, eTag: String?, for endpoint: String) {
        let fileURL = cacheDirectory.appendingPathComponent(endpoint.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? "cache")
        try? data.write(to: fileURL)
        
        if let eTag = eTag {
            UserDefaults.standard.set(eTag, forKey: "etag_\(endpoint)")
        }
    }
    
    public func getCachedSnapshot(for endpoint: String) -> (data: Data, eTag: String?)? {
        let fileURL = cacheDirectory.appendingPathComponent(endpoint.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? "cache")
        guard let data = try? Data(contentsOf: fileURL) else { return nil }
        let eTag = UserDefaults.standard.string(forKey: "etag_\(endpoint)")
        return (data, eTag)
    }
}
```

---

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

<details>
<summary><b>1-Savol: Nega parslash jarayonida 'autoreleasepool' blokini ishlatish xotira to'lib ketishining oldini oladi?</b> (Yechimni ko'rish uchun bosing)</summary>

**Tahlil va Yechim:**
`JSONDecoder` parslash jarayonida millionlab kichik vaqtinchalik `String`, `Substring` va `Dictionary` obyektlarini yaratadi. Odatda bu obyektlar RunLoop tugaguncha xotirada qolib ketadi. `autoreleasepool { ... }` ishlatilganda, blok yakunlanishi bilanoq barcha vaqtinchalik obyektlar darhol RAM'dan o'chiriladi va xotira cho'qqisi (Memory Spike) sababli ilovaning iOS tomonidan o'ldirilishi (Jetsam OOM) oldi olinadi.
</details>

<details>
<summary><b>2-Savol: HTTP 304 Not Modified statusi SDUI tizimlariga qanday foyda keltiradi?</b> (Yechimni ko'rish uchun bosing)</summary>

**Tahlil va Yechim:**
Mobil ilova so'rov yuborayotganda keshdagi ETag qiymatini `If-None-Match` sarlavhasida jo'natadi. Agar serverda ma'lumot o'zgarmagan bo'lsa, server bo'sh (0 baytlik) `304` javobini qaytaradi. Bu foydalanuvchi mobil trafigini tejaydi, batareya quvvatini sarflamaydi va serverdagi ma'lumotlar bazasi yuklamasini keskin kamaytiradi.
</details>

---

## 6. Amaliy Topshiriq (Senior Challenge)

O'z loyihangizda `SDUIDataEngine` actorini yarating. 10 000 ta obyektdan iborat sintetik JSON ma'lumotini avval `Main Thread`da, so'ngra `actor` orqali fonda pars qilib ko'ring. `CFAbsoluteTimeGetCurrent()` orqali vaqtlarni solishtiring va konsolda natijani qayd eting.
