Azimjon Abdurasulov

Swift Concurrency

Cheat Sheet'lar

Swift Concurrency Cheat Sheet

Swift 5.5+ versiyasidan boshlab joriy qilingan zamonaviy asinxron dasturlash modeli: async/await, Task, Actor va Structured Concurrency bo'yicha tezkor qo'llanma.


1. async / await Asoslari

// Asinxron funksiya e'lon qilish
func fetchUser(id: String) async throws -> User {
    let url = URL(string: "https://api.example.com/users/\(id)")!
    let (data, response) = try await URLSession.shared.data(from: url)
    
    guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
        throw NetworkError.badServerResponse
    }
    return try JSONDecoder().decode(User.self, from: data)
}

// Chaqirish
Task {
    do {
        let user = try await fetchUser(id: "101")
        print("Foydalanuvchi:", user.name)
    } catch {
        print("Xatolik:", error)
    }
}

2. Task va Bekor Qilish (Task & Cancellation)

// 1. Yangi Task yaratish (Ota kontekstning actor va prioritetini meros oladi)
let task = Task(priority: .userInitiated) {
    for i in 1...100 {
        // Har qadamda bekor qilinganini tekshirish:
        try Task.checkCancellation()
        
        // Yoki if orqali:
        if Task.isCancelled { break }
        
        // 1 soniya kutish (thread bloklanmaydi)
        try await Task.sleep(nanoseconds: 1_000_000_000)
        print("Qadam \(i)")
    }
}

// Taskni to'xtatish
task.cancel()

// 2. Detached Task (Kontekstdan butunlay ajralgan yangi mustaqil task)
Task.detached(priority: .background) {
    await performHeavyCalculation()
}

3. Structured Concurrency: async let va TaskGroup

async let — Bir nechta so'rovni parallel bajarish:

func loadDashboardData() async throws -> (Profile, Feed, [Notification]) {
    // Har biri bir vaqtda parallel ishga tushadi
    async let userProfile = fetchProfile()
    async let userFeed = fetchFeed()
    async let notifications = fetchNotifications()

    // Barchasining natijasi tayyor bo'lguncha kutadi
    return try await (userProfile, userFeed, notifications)
}

TaskGroup — Dinamik miqdordagi parallel vazifalar:

func downloadImages(urls: [URL]) async throws -> [UIImage] {
    try await withThrowingTaskGroup(of: UIImage.self) { group in
        for url in urls {
            group.addTask {
                let (data, _) = try await URLSession.shared.data(from: url)
                guard let image = UIImage(data: data) else {
                    throw ImageError.corruptData
                }
                return image
            }
        }

        var images: [UIImage] = []
        for try await image in group {
            images.append(image)
        }
        return images
    }
}

4. Actors & Data Isolation (Thread Safety)

actor reference type bo'lib, o'zining ichki holatini data race'lardan (bir vaqtda bir nechta threaddan o'qish/yozish) avtomatik himoyalaydi.

actor BankAccount {
    private var balance: Double = 0.0

    func deposit(amount: Double) {
        balance += amount
    }

    func withdraw(amount: Double) -> Bool {
        guard balance >= amount else { return false }
        balance -= amount
        return true
    }

    // Actor ichida data race xavfi bo'lmagan konstantalar uchun:
    nonisolated let accountNumber = "123-456"
}

// Ishlatish: tashqaridan chaqirganda har doim 'await' qo'yiladi
let account = BankAccount()
await account.deposit(amount: 50.0)
let success = await account.withdraw(amount: 20.0)

5. @MainActor

UI bilan bog'liq barcha amallar Main Thread'da bajarilishini kafolatlaydi.

@MainActor
final class ProfileViewModel: ObservableObject {
    @Published var username: String = ""

    func loadProfile() async {
        // Tarmoq so'rovi background threadda bajariladi
        let name = await NetworkService.shared.getName()
        // Bu qator avtomatik Main Threadda ishlaydi
        self.username = name
    }
}

// Istalgan joydan Main Threadga o'tish:
await MainActor.run {
    view.backgroundColor = .systemGreen
}

6. Sendable va @Sendable

Concurrency kontekstlari (threadlar va tasklar) o'rtasida xavfsiz uzatilishi mumkin bo'lgan turlar Sendable protokoliga to'g'ri keladi.

  • Avtomatik Sendable: Value type'lar (struct, enum), oddiy turlar (Int, String), va actor.
  • Class'lar: Faqat final bo'lsa va faqat let (o'zgarmas) Sendable xususiyatlarga ega bo'lsagina Sendable bo'la oladi.
// Sendable Struct
struct UserDTO: Sendable {
    let id: String
    let email: String
}

// @Sendable Closure
func executeInBackground(work: @Sendable @escaping () -> Void) {
    Task.detached {
        work()
    }
}

7. AsyncStream (Asinxron Oqimlar)

Callback yoki NotificationCenter asosidagi eski API'larni zamonaviy for await oqimiga aylantirish:

func locationUpdates() -> AsyncStream<CLLocation> {
    AsyncStream { continuation in
        let manager = LocationManagerHelper()
        manager.onUpdate = { location in
            continuation.yield(location) // Yangi element chiqarish
        }
        manager.onError = {
            continuation.finish() // Oqimni tugatish
        }
        continuation.onTermination = { _ in
            manager.stopUpdating()
        }
    }
}

// Ishlatilishi:
Task {
    for await location in locationUpdates() {
        print("Yangi koordinata:", location.coordinate)
    }
}

8. GCD (Eski) vs Swift Concurrency (Yangi) Taqqoslash

Eski usul (Grand Central Dispatch)Yangi usul (Swift Concurrency)
DispatchQueue.main.async { ... }@MainActor yoki await MainActor.run { ... }
DispatchQueue.global().async { ... }Task { ... } yoki Task.detached { ... }
DispatchGroup (enter(), leave())async let yoki withTaskGroup
Thread.sleep(forTimeInterval: 1.0)try await Task.sleep(nanoseconds: 1_000_000_000)
completionHandler: @escaping (Result<T, Error>) -> Voidfunc doWork() async throws -> T
NSLock / os_unfair_lock / Serial Queueactor

Markdown manba

iOS Lessons