# 04. Client Rendering Engine (SwiftUI & UIKit): 120 FPS Tezlikda Chizish

> "SwiftUI tabiatan juda tezkor, ammo ko'plab SDUI dasturchilari `AnyView` ni bilimsizlik bilan ishlatib, uni 15 FPS lik qotadigan ilovaga aylantirib qo'yishadi. Senior dasturchining vazifasi — SwiftUI ning Structural Identity mexanizmini saqlab qolishdir."

---

## 1. SwiftUI Rendering Dvigateli: Structural Identity Nima?

SwiftUI ekranni qayta chizishda virtual DOM yoki DOM Tree ishlatmaydi. Buning o'rniga u Apple tomonidan ishlab chiqilgan **AttributeGraph** mexanizmiga tayanadi.

AttributeGraph har bir View ning statik turini (Type Signature) kompilyatsiya vaqtida bilishi kerak:
```swift
// SwiftUI bu turni aniq biladi:
VStack<TupleView<(Image, Text, Button<Text>)>>
```

Barcha o'zgarishlar faqat o'sha komponentga taalluqli bo'ladi. Agar siz `AnyView` ishlatsangiz nima bo'ladi?

```mermaid
flowchart TD
    subgraph BadCase["❌ AnyView Bilan: Structural Identity Yo'qoladi"]
        direction TB
        AV1["AnyView(BannerView)"] -->|"Type Erasure!"| AG1["AttributeGraph: Tip noma'lum!"]
        AG1 -->|"Scroll yoki State o'zgarganda"| Recreate["Butun View daraxti Heap'dan qayta yaratiladi!\nDrop Frame! Jank! RAM shishishi!"]
    end

    subgraph GoodCase["✅ ComponentRegistry + Identifiable Bilan"]
        direction TB
        CR1["Registry.resolve(node)"] -->|"id: node.id saqlanadi"| AG2["AttributeGraph: Identifikator ma'lum!"]
        AG2 -->|"Faqat o'zgargan komponent"| Patch["Faqat kerakli element yangilanadi!\nSilliq 120 FPS ProMotion!"]
    end

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

---

## 2. Professional Component Registry Dvigateli

Type Erasure zararini minimal darajaga tushirish va yangi komponentlarni dinamik ulash uchun markaziy `ComponentRegistry` arxitekturasi qo'llaniladi.

```mermaid
graph LR
    subgraph RegistryCenter["Markaziy ComponentRegistry"]
        Reg["ComponentRegistry.shared"]
        Reg -->|"type: 'banner'"| B1["BannerComponentView()"]
        Reg -->|"type: 'carousel'"| B2["CarouselComponentView()"]
        Reg -->|"type: 'button'"| B3["PrimaryButtonView()"]
        Reg -->|"type: 'unknown'"| B4["UnknownFallbackView()"]
    end

    Node["ComponentNode\n{ id, type, props }"] --> Reg
    Reg --> Output["120 FPS Native SwiftUI View"]
```

### Swift 6 da To'liq Ishlovchi Registry Kodi:

```swift
import SwiftUI

// MARK: - 1. Komponent Renderer Protokoli
public protocol SDUIComponentView: Sendable {
    associatedtype Content: View
    @ViewBuilder @MainActor func makeView(node: ComponentNode) -> Content
}

// MARK: - 2. Markaziy Registry Sinfi
@MainActor
public final class ComponentRegistry {
    public static let shared = ComponentRegistry()
    
    // Ro'yxatga olingan komponentlar lug'ati
    private var builders: [String: @MainActor (ComponentNode) -> AnyView] = [:]
    
    private init() {
        registerDefaultComponents()
    }
    
    /// Yangi komponentni ro'yxatdan o'tkazish
    public func register<V: View>(
        type: String,
        @ViewBuilder builder: @escaping @MainActor (ComponentNode) -> V
    ) {
        builders[type] = { node in
            AnyView(builder(node))
        }
    }
    
    /// JSON tugunini xavfsiz SwiftUI View'ga aylantirish
    @ViewBuilder
    public func resolve(node: ComponentNode) -> some View {
        if let builder = builders[node.type] {
            builder(node)
                .id(node.id) // SwiftUI diffing va animatsiyalar uchun majburiy!
        } else {
            UnknownComponentFallbackView(node: node)
        }
    }
    
    private func registerDefaultComponents() {
        // Tizimning standart bazaviy komponentlari
        register(type: "space") { node in
            let height = (node.props["height"]?.value as? Double) ?? 16.0
            Spacer().frame(height: height)
        }
        
        register(type: "divider") { _ in
            Divider()
        }
    }
}
```

---

## 3. UnknownComponentFallbackView: Crashga Qarshi Xavfsizlik Devori

Agar foydalanuvchida eski ilova versiyasi bo'lsa va server yangi komponent yuborsa, ilova qanday reaksiyada bo'lishi kerak?

```swift
import SwiftUI

public struct UnknownComponentFallbackView: View {
    public let node: ComponentNode
    
    public var body: some View {
        #if DEBUG
        // 🛠 Dasturchi xatosini ko'rishi uchun qizil informatsion karta
        VStack(alignment: .leading, spacing: 6) {
            HStack {
                Image(systemName: "exclamationmark.triangle.fill")
                    .foregroundColor(.yellow)
                Text("Noma'lum Komponent: '\(node.type)'")
                    .font(.caption.monospaced().bold())
                    .foregroundColor(.red)
            }
            Text("Ushbu komponent turi ilova registratorida ro'yxatdan o'tmagan.")
                .font(.caption2)
                .foregroundColor(.secondary)
        }
        .padding(10)
        .frame(maxWidth: .infinity, alignment: .leading)
        .background(Color.red.opacity(0.12))
        .cornerRadius(8)
        .overlay(
            RoundedRectangle(cornerRadius: 8)
                .stroke(Color.red.opacity(0.3), lineWidth: 1)
        )
        .padding(.horizontal, 16)
        .padding(.vertical, 4)
        #else
        // 🚀 App Store (Production) rejimida: Foydalanuvchiga hech narsa bildirilmaydi!
        // Ekran tartibi va boshqa komponentlar buzilmasdan ko'rinaveradi
        EmptyView()
        #endif
    }
}
```

---

## 4. UIKit Loyihalari Uchun Renderer (CompositionalLayout + DiffableDataSource)

Agar siz UIKit ishlatilayotgan yirik loyihada (masalan, Uber yoki Airbnb Epoxy uslubida) SDUI qursangiz:

```mermaid
flowchart LR
    SDUIPayload["SDUIScreenPayload"] --> Diffable["UICollectionViewDiffableDataSource"]
    Diffable -->|"NSDiffableDataSourceSnapshot"| Layout["UICollectionViewCompositionalLayout"]
    Layout --> Collection["120 FPS UICollectionView"]
```

```swift
import UIKit

public final class SDUICollectionViewController: UIViewController {
    private var collectionView: UICollectionView!
    private var dataSource: UICollectionViewDiffableDataSource<String, ComponentNode>!
    
    public override func viewDidLoad() {
        super.viewDidLoad()
        setupCollectionView()
        configureDataSource()
    }
    
    private func setupCollectionView() {
        let layout = UICollectionViewCompositionalLayout { sectionIndex, env in
            let itemSize = NSCollectionLayoutSize(
                widthDimension: .fractionalWidth(1.0),
                heightDimension: .estimated(100)
            )
            let item = NSCollectionLayoutItem(layoutSize: itemSize)
            let group = NSCollectionLayoutGroup.vertical(layoutSize: itemSize, subitems: [item])
            return NSCollectionLayoutSection(group: group)
        }
        
        collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
        collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(collectionView)
    }
    
    private func configureDataSource() {
        // Universal Cell Registration
        let cellRegistration = UICollectionView.CellRegistration<UICollectionViewCell, ComponentNode> { cell, indexPath, node in
            cell.contentConfiguration = UIHostingConfiguration {
                ComponentRegistry.shared.resolve(node: node)
            }
        }
        
        dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { collectionView, indexPath, node in
            collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: node)
        }
    }
    
    public func update(components: [ComponentNode]) {
        var snapshot = NSDiffableDataSourceSnapshot<String, ComponentNode>()
        snapshot.appendSections(["main"])
        snapshot.appendItems(components)
        dataSource.apply(snapshot, animatingDifferences: true)
    }
}
```

---

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

<details>
<summary><b>1-Savol: Nega SDUIScreenView'da oddiy VStack o'rniga LazyVStack ishlatilishi shart?</b> (Yechimni ko'rish uchun bosing)</summary>

**Tahlil va Yechim:**
Oddiy `VStack` ekranda nechta element bo'lsa (masalan, 200 ta kartochka), ularning barchasini birdaniga (bir vaqtda) xotiraga yuklaydi va render qiladi. Bu esa xotirani (RAM) to'ldirib, ekranni qotiradi. `LazyVStack` esa faqat ekranda ko'rinayotgan 5-10 ta elementni chizadi, qolganlarini esa foydalanuvchi scroll qilgan sari dinamik yuklaydi (View Virtualization).
</details>

<details>
<summary><b>2-Savol: UIHostingConfiguration nima va u UIKit loyihalarida SDUI ga qanday yordam beradi?</b> (Yechimni ko'rish uchun bosing)</summary>

**Tahlil va Yechim:**
iOS 16 da taqdim etilgan `UIHostingConfiguration` UIKit'dagi `UICollectionViewCell` ichiga to'g'ridan-to'g'ri SwiftUI View'ni o'rnatish imkonini beradi. Eskicha `UIHostingController` ochib, uni child view controller qilib qo'shish shart emas. Natijada UIKit'ning yuqori unumdorlikka ega Diffable DataSource'i va SwiftUI'ning deklarativ komponentlari birlashadi.
</details>

---

## 6. Amaliy Topshiriq (Senior Challenge)

`ComponentRegistry` ga 2 ta native komponentni ro'yxatdan o'tkazing:
1. `"crypto_ticker"` -> Valyuta kursi, foiz o'zgarishi va mitti sparkline grafik.
2. `"order_status_banner"` -> Buyurtma holati va progress indikatori.

So'ngra ushbu komponentlarni serverdan kelgan JSON simulyatsiyasi orqali SwiftUI ekranda 120 FPS tezlikda render qilib ko'ring!
