Azimjon Abdurasulov

07. Cache va Optimizatsiya

🚀 Tuist — Mukammal Qo‘llanma & Amaliyot

⚡ Cache, Build Optimization va Debugging

"Vaqt — eng qimmat resurs. Tuist cache bilan 15 daqiqalik build'ni 15 soniyaga tushiring!"


Binary Caching nima?

Binary Caching — bu Tuist'ning eng kuchli feature'laridan biri. U o'zgarmagan modullarni qayta compile qilish o'rniga, oldindan tayyor qilingan binary (xcframework) sifatida ishlatadi.

Muammo

Loyihangizda 20 ta module bor:
├── CoreModule          (o'zgarMAgan ❌)
├── NetworkKit          (o'zgarMAgan ❌)
├── DesignSystem        (o'zgarMAgan ❌)
├── HomeFeature         (O'ZGARGAN ✅)  ← faqat shu 1 ta
├── ProfileFeature      (o'zgarMAgan ❌)
└── ... (yana 15 ta o'zgarMAgan modul)

❌ Xcode: Barcha 20 ta modulni qayta compile qiladi → 15 daqiqa
✅ Tuist: Faqat HomeFeature compile qiladi, qolganlar binary → 15 soniya

Qanday ishlaydi?

1-Qadam: tuist cache
┌─────────────────────────────────────────┐
│ Tuist har bir modulni compile qiladi    │
│ va .xcframework formatda saqlaydi       │
│                                         │
│ CoreModule.xcframework      → Cache ✅  │
│ NetworkKit.xcframework      → Cache ✅  │
│ DesignSystem.xcframework    → Cache ✅  │
│ HomeFeature.xcframework     → Cache ✅  │
│ ProfileFeature.xcframework  → Cache ✅  │
└─────────────────────────────────────────┘

2-Qadam: Siz HomeFeature da kod o'zgartirdingiz

3-Qadam: tuist generate HomeFeature
┌─────────────────────────────────────────┐
│ CoreModule      → Binary (cache dan) ⚡ │
│ NetworkKit      → Binary (cache dan) ⚡ │
│ DesignSystem    → Binary (cache dan) ⚡ │
│ HomeFeature     → SOURCE (compile) 🔨   │
│ ProfileFeature  → Binary (cache dan) ⚡ │
└─────────────────────────────────────────┘

Cache Buyruqlari

tuist cache — Modullarni Cache'lash

# Barcha modullarni cache'lash
tuist cache

# Faqat dependency'larni cache'lash (o'zingiz ishlayotgan modulni emas)
tuist cache --dependencies-only

# Ma'lum modulni cache'lash
tuist cache CoreModule NetworkKit

Cache'dan foydalanish

# Barcha cache'langan modullarni binary bilan generate
tuist generate

# Faqat bitta feature ni generate (qolganlar binary)
tuist generate HomeFeature

Cache Tozalash

# Cache tozalash
tuist clean

Hashing Mexanizmi

Tuist har bir module uchun hash hisoblab, o'zgarganligini aniqlaydi.

Nima hisobga olinadi?

Ma'lumotMisol
Source fayllariHomeView.swift mazmuni
Resource fayllariAssets.xcassets, rasmlar
DependenciesCoreModule hash'i
Build settingsCompiler flaglar, optimization level
Swift versiyaSWIFT_VERSION = 5.9

Hash qanday ishlaydi?

HomeFeature hash = SHA256(
    HomeView.swift +
    HomeViewModel.swift +
    Assets.xcassets +
    CoreModule.hash +     ← dependency hash
    build_settings +
    swift_version
)

Agar hash o'zgarMAsa → cache'dan binary ishlating
Agar hash o'zgarSA → qayta compile qiling

Cache bir nechta kompyuterda

Tuist Server (cloud) bilan cache jamoa bo'ylab ulashiladi:

# Tuist Cloud auth
tuist auth

# Cache'ni upload qilish
tuist cache --upload

# Boshqa dasturchi download qiladi
tuist generate  # Avtomatik cloud cache'dan oladi

Foyda: Dasturchi A CoreModule ni cache'ladi → Dasturchi B uni compile qilmasdan binary oladi.


Xcode Build Optimization

Tuist'dan tashqari, Xcode'ning o'zi ham build'ni tezlashtirish sozlamalari bor.

1. Parallel Builds (Parallel Qurilish)

Xcode → Build Settings:

PARALLEL_BUILD = YES    # (Default: YES)

Xcode bir vaqtda bir nechta target'ni compile qila oladi — agar ular bir-biriga bog'liq bo'lmasa.

┌─────────────┐  ┌─────────────┐  ┌─────────────┐
│  CoreModule  │  │ DesignSystem│  │  Analytics  │
│  (Thread 1)  │  │  (Thread 2) │  │  (Thread 3) │
└──────┬───────┘  └──────┬──────┘  └──────┬──────┘
       │                 │                │
       └────────┬────────┘                │
                │                         │
       ┌────────▼────────┐                │
       │   HomeFeature   │────────────────┘
       │   (Thread 1)    │
       └────────┬────────┘
                │
       ┌────────▼────────┐
       │     MyApp       │
       └─────────────────┘

2. Incremental Builds

Xcode faqat o'zgargan fayllarni qayta compile qiladi. Buning ishlashi uchun:

✅ Derived Data'ni o'chirmang (Clean build sekin!)
✅ Build folder yagona bo'lsin
✅ Module'lar kichik bo'lsin (TMA bilan!)

3. Build Timing Summary

Qaysi fayl/target eng sekin compile bo'layotganini aniqlash:

# Xcode da build time ko'rsatish
defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES

# xcodebuild bilan timing summary
xcodebuild build \
    -workspace MyApp.xcworkspace \
    -scheme MyApp \
    -showBuildTimingSummary

Natija (misol):

CompileSwift (1 file) HomeView.swift         0.8s
CompileSwift (1 file) HomeViewModel.swift     0.3s
CompileSwift (1 file) NetworkClient.swift     2.1s  ← SEKIN!
Ld                    HomeFeature.framework   0.2s

NetworkClient.swift 2.1 soniya! — Bu faylni optimize qilish kerak (masalan, generics'ni kamaytirish yoki faylni bo'laklash).

4. Compilation Mode

// Debug uchun — Incremental (tezroq)
SWIFT_COMPILATION_MODE = incremental

// Release uchun — Whole Module (optimizatsiya)
SWIFT_COMPILATION_MODE = wholemodule

**wholemodule — Swift compiler butun modulni bir vaqtda compile qiladi. Bu ko'proq optimizatsiya imkonini beradi lekin sekinroq. incremental** — Faqat o'zgargan fayllarni compile qiladi. Tezroq lekin kamroq optimizatsiya.

5. Build Active Architecture Only

// Debug uchun — faqat joriy arxitektura (tezroq)
ONLY_ACTIVE_ARCH = YES

// Release uchun — barcha arxitekturalar
ONLY_ACTIVE_ARCH = NO

Tuist da sozlash:

settings: .settings(
    base: [
        "ONLY_ACTIVE_ARCH[config=Debug]": "YES",
        "ONLY_ACTIVE_ARCH[config=Release]": "NO",
    ]
)

Xcode Indexing va Cache

Indexing nima?

Xcode index — bu loyihadagi barcha symbol'lar (function'lar, class'lar, protocol'lar) haqida ma'lumot bazasi. U quyidagilar uchun kerak:

  • ✅ Autocomplete — kod yozayotganda tavsiyalar
  • ✅ Jump to Definition — Cmd+Click bilan deklaratsiyaga o'tish
  • ✅ Find Usages — symbol qayerda ishlatilganini topish
  • ✅ Syntax Highlighting — kod ranglanishi

Index qayerda saqlanadi?

~/Library/Developer/Xcode/DerivedData/
└── MyApp-abc123def/
    ├── Build/                  ← Build artifacts
    └── Index.noindex/          ← INDEX DATABASE
        └── DataStore/

Cache bilan Index qanday ishlaydi?

Tuist binary cache ishlatganda — pre-built module larning index'i ham tayyor bo'ladi:

Cached module (binary):
├── CoreModule.xcframework      ← Compile qilingan kod
├── CoreModule.swiftmodule      ← Swift interface (autocomplete uchun)
└── CoreModule.swiftdoc         ← Dokumentatsiya

→ Xcode bu fayllardan INDEX yaratadi — compile qilmasdan!
→ Autocomplete va Jump to Definition ishlaydi ✅

Index muammolari va hal qilish

MuammoYechim
Autocomplete ishlamayaptiCmd+Shift+K (Clean) yoki Derived Data o'chirish
"Indexing..." doimiy ko'rsatadiLoyihani yoping, Derived Data o'chiring, qayta oching
Binary module'da autocomplete yo'q.swiftmodule fayl borligini tekshiring
Index juda sekinModule'larni kichiklating (TMA bilan)
# Derived Data to'liq tozalash
rm -rf ~/Library/Developer/Xcode/DerivedData

# Faqat bitta loyiha uchun
rm -rf ~/Library/Developer/Xcode/DerivedData/MyApp-*

Tuist Loyihalarida Debugging

1. Breakpoints

Tuist bilan generate qilingan loyihada breakpoints oddiy Xcode loyiha kabi ishlaydi.

// HomeViewModel.swift
func loadProducts() async {
    isLoading = true
    do {
        products = try await service.fetchProducts()  // ← Breakpoint qo'ying
        isLoading = false
    } catch {
        errorMessage = error.localizedDescription
        isLoading = false
    }
}

Muhim: Binary cache'dan kelgan module'larda breakpoint qo'yish mumkin emas (chunki source kod yo'q). Agar debug qilmoqchi bo'lsangiz — o'sha module'ni source'dan generate qiling:

# Faqat debug qilmoqchi bo'lgan module'ni source bilan
tuist generate HomeFeature CoreModule
# CoreModule source bo'lgani uchun — breakpoint qo'yish mumkin

2. LLDB — Terminal Debugging

Xcode debug paytida LLDB console'da:

// O'zgaruvchi qiymatini ko'rish
(lldb) po products
// → [Product(id: "1", name: "iPhone"), Product(id: "2", name: "MacBook")]

// O'zgaruvchi o'zgartirish
(lldb) expr isLoading = false

// Function chaqirish
(lldb) expr service.fetchProducts()

// Memory address ko'rish
(lldb) p &products

3. Scheme Settings — Debug Configuration

Project.swift da debug uchun maxsus sozlamalar:

schemes: [
    .scheme(
        name: "MyApp-Debug",
        shared: true,
        buildAction: .buildAction(targets: ["MyApp"]),
        runAction: .runAction(
            configuration: .debug,
            executable: "MyApp",
            arguments: .arguments(
                environmentVariables: [
                    "ENABLE_LOGGING": .environmentVariable(value: "1", isEnabled: true),
                    "API_BASE_URL": .environmentVariable(
                        value: "https://staging.api.example.com",
                        isEnabled: true
                    ),
                ],
                launchArguments: [
                    .launchArgument(name: "-com.apple.CoreData.SQLDebug 1", isEnabled: true),
                    .launchArgument(name: "-UITesting", isEnabled: false),
                ]
            )
        ),
        testAction: .targets(
            ["MyAppTests"],
            configuration: .debug,
            options: .options(coverage: true)
        )
    )
]

4. Environment Variables bilan Debug

// AppDelegate yoki App.swift da
#if DEBUG
let baseURL = ProcessInfo.processInfo.environment["API_BASE_URL"]
    ?? "https://api.example.com"
#else
let baseURL = "https://api.example.com"
#endif

5. Network Debugging

// Tuist manifest da NSAllowsArbitraryLoads
infoPlist: .extendingDefault(with: [
    "NSAppTransportSecurity": [
        "NSAllowsArbitraryLoads": true,  // ⚠️ Faqat Debug uchun!
    ],
])

Build Vaqtini O'lchash

Xcode Build Time ko'rsatish

# Terminal da yoqish
defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES

# Xcode'ni qayta ishga tushiring
# Endi build tugaganda vaqt ko'rinadi:
# "Build: Succeeded | 12.3s"

xcodebuild Timing Summary

xcodebuild build \
    -workspace MyApp.xcworkspace \
    -scheme MyApp \
    -destination "platform=iOS Simulator,name=iPhone 16" \
    -showBuildTimingSummary 2>&1 | tail -20

Natija:

Build Timing Summary
CompileSwift          35 tasks    24.5s
Ld                    8 tasks     3.2s
CopySwiftLibs         1 task      0.5s
ProcessInfoPlistFile  2 tasks     0.1s
Total                             28.3s

Sekin Compile bo'ladigan Fayllarni Topish

Xcode → Product → Build Settings ga qo'shing:

OTHER_SWIFT_FLAGS = $(inherited) -Xfrontend -warn-long-function-bodies=200
-Xfrontend -warn-long-expression-type-checking=200

Bu 200ms dan uzoq compile bo'ladigan function/expression'lar uchun warning beradi.


Selective Testing

Tuist faqat o'zgargan modul va unga bog'liq modul'larni test qiladi:

# Barcha testlarni ishga tushirish
tuist test

# Faqat o'zgargan modullarning testlarini
tuist test --selective
O'zgargan modul: CoreModule

Tuist aniqlaydi:
├── CoreModule        → TEST ✅ (o'zgargan)
├── HomeFeature       → TEST ✅ (CoreModule ga bog'liq)
├── ProfileFeature    → TEST ✅ (CoreModule ga bog'liq)
├── DesignSystem      → SKIP ⏭️ (CoreModule ga bog'liq EMAS)
└── Analytics         → SKIP ⏭️ (CoreModule ga bog'liq EMAS)

Natija: 3 ta modul test qilindi (5 ta o'rniga)

CI/CD da Cache Strategiyasi

GitHub Actions misol

# .github/workflows/build.yml
name: Build & Test

on: [push, pull_request]

jobs:
  build:
    runs-on: macos-14
    steps:
      - uses: actions/checkout@v4

      # Mise bilan Tuist o'rnatish
      - name: Install Mise
        run: curl https://mise.run | sh

      - name: Install Tuist
        run: mise install tuist

      # Cache restore
      - name: Restore Tuist Cache
        uses: actions/cache@v3
        with:
          path: ~/.tuist/Cache
          key: tuist-cache-${{ hashFiles('**/*.swift') }}

      # Build
      - name: Install Dependencies
        run: tuist install

      - name: Generate
        run: tuist generate --no-open

      - name: Build
        run: tuist build

      # Test (selective)
      - name: Test
        run: tuist test

Xulosa

FeatureBuyruqFoyda
Binary Cachetuist cacheBuild vaqtini ~10x tezlashtirish
Selective Testingtuist test --selectiveFaqat o'zgargan modullarni test
Build Timing-showBuildTimingSummarySekin fayllarni aniqlash
Parallel BuildPARALLEL_BUILD=YESModullarni parallel compile
DebuggingBreakpoints, LLDB, Scheme env varsXcode'dek oddiy debug

💡 Keyingi darslik: Code Sharing, Templates va App Store Publish — ProjectDescriptionHelpers, plugins, va App Store ga chiqarish.

"Tez build = tez development = tez delivery. Cache — bu sizning superkuchingiz!" ⚡

Markdown manba

iOS Lessons