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'lumot | Misol |
|---|---|
| Source fayllari | HomeView.swift mazmuni |
| Resource fayllari | Assets.xcassets, rasmlar |
| Dependencies | CoreModule hash'i |
| Build settings | Compiler flaglar, optimization level |
| Swift versiya | SWIFT_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
CoreModuleni 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.swift2.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
| Muammo | Yechim |
|---|---|
| Autocomplete ishlamayapti | Cmd+Shift+K (Clean) yoki Derived Data o'chirish |
| "Indexing..." doimiy ko'rsatadi | Loyihani yoping, Derived Data o'chiring, qayta oching |
| Binary module'da autocomplete yo'q | .swiftmodule fayl borligini tekshiring |
| Index juda sekin | Module'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
| Feature | Buyruq | Foyda |
|---|---|---|
| Binary Cache | tuist cache | Build vaqtini ~10x tezlashtirish |
| Selective Testing | tuist test --selective | Faqat o'zgargan modullarni test |
| Build Timing | -showBuildTimingSummary | Sekin fayllarni aniqlash |
| Parallel Build | PARALLEL_BUILD=YES | Modullarni parallel compile |
| Debugging | Breakpoints, LLDB, Scheme env vars | Xcode'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!" ⚡