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), vaactor. - Class'lar: Faqat
finalbo'lsa va faqatlet(o'zgarmas)Sendablexususiyatlarga 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>) -> Void | func doWork() async throws -> T |
NSLock / os_unfair_lock / Serial Queue | actor |