- Published on
Swiftda AsyncSequence va AsyncStream
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
AsyncSequence — oddiy Sequence (Array, Range) ning asinxron versiyasi. Oddiy ketma-ketlikda barcha elementlar tayyor va bir zumda olinadi. AsyncSequence da esa elementlar vaqt o'tishi bilan keladi — masalan, tarmoqdan ma'lumot, sensor o'qishlari, yoki timer signallari. Har bir elementni olish uchun for await loop ishlatiladi.
AsyncStream — o'zingiz yaratadigan AsyncSequence. continuation.yield() bilan qiymatlar yuborasiz, continuation.finish() bilan stream ni tugatansiz. Bu eski callback-based API larni asinxron oqimga aylantirish uchun juda qulay.
AsyncSequence asoslari
Apple ko'p API larini allaqachon AsyncSequence sifatida beradi. URL.lines — faylni satr-satr asinxron o'qiydi (katta fayllar uchun xotira tejaydi). URLSession.bytes — tarmoqdan ma'lumotni bayt-bayt stream qiladi. Bundan tashqari, .map(), .filter(), .prefix() kabi transformatsiyalar ham asinxron ishlaydi.
// ═══════════════════════════════════════
// URL.lines — faylni satr-satr asinxron o'qish
// ═══════════════════════════════════════
func satrlarniOqish() async throws {
let url = URL(string: "https://example.com/katta-fayl.txt")!
// for await — har satr kelguncha kutadi
for try await satr in url.lines {
print(satr)
// Katta faylni xotiraga to'liq yuklamaydi
// Har satr kelganda qayta ishlaydi
}
}
// ═══════════════════════════════════════
// URLSession.bytes — baytlarni stream qilish
// ═══════════════════════════════════════
func yuklanishniKuzatish() async throws {
let url = URL(string: "https://example.com/rasm.jpg")!
let (bytes, response) = try await URLSession.shared.bytes(from: url)
let totalSize = Int(response.expectedContentLength)
var received = 0
for try await byte in bytes {
received += 1
if received % 1024 == 0 {
let foiz = Double(received) / Double(totalSize) * 100
print("Yuklandi: \(Int(foiz))%")
}
}
}
// ═══════════════════════════════════════
// TRANSFORMATSIYALAR — map, filter va boshqalar
// ═══════════════════════════════════════
func filtrlash() async throws {
let url = URL(string: "https://example.com/log.txt")!
// filter va map — asinxron ishlaydi
for try await satr in url.lines
.filter({ $0.contains("ERROR") }) // Faqat xato satrlari
.map({ $0.uppercased() }) // Katta harfga
.prefix(10) // Faqat 10 ta
{
print("XATO: \(satr)")
}
}
AsyncStream yaratish
AsyncStream — o'z asinxron ketma-ketligingizni yaratish uchun. Uning asosiy qismi continuation — bu orqali qiymatlar yuboriladi va stream tugatiladi. Masalan, har soniyada son yuboradigan sanagich yoki harorat sensor dan ma'lumot oqimi yaratish mumkin. Stream bekor qilinganda onTermination callback orqali resurslarni tozalash mumkin.
// ═══════════════════════════════════════
// ASYNCSTREAM — o'z async ketma-ketligingiz
// ═══════════════════════════════════════
func sanagich(gacha: Int, interval: Duration = .seconds(1)) -> AsyncStream<Int> {
AsyncStream { continuation in
// continuation — qiymat yuborish uchun
Task {
for i in 1...gacha {
try? await Task.sleep(for: interval)
// yield — keyingi qiymatni yuborish
continuation.yield(i)
}
// finish — stream tugadi
continuation.finish()
}
}
}
// Ishlatish
Task {
// for await — har soniya bitta son keladi
for await son in sanagich(gacha: 5) {
print("Son: \(son)")
}
// 1, 2, 3, 4, 5 — har biri 1 soniya oraliqda
print("Tugadi!")
}
// ═══════════════════════════════════════
// SENSOR MA'LUMOTLARI — real-time stream
// ═══════════════════════════════════════
func haroratOqimi() -> AsyncStream<Double> {
AsyncStream { continuation in
// Timer har 2 soniyada yangi harorat yuboradi
let timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { _ in
let harorat = Double.random(in: 20...35)
continuation.yield(harorat)
}
// Stream bekor qilinganda timer ni to'xtatish
continuation.onTermination = { _ in
timer.invalidate()
}
}
}
Task {
for await harorat in haroratOqimi() {
print("Harorat: \(harorat)°C")
if harorat > 33 {
print("⚠️ Issiq!")
break // Stream dan chiqish
}
}
}
AsyncThrowingStream — xato bilan
Agar stream da xato bo'lishi mumkin bo'lsa — AsyncThrowingStream ishlatiladi. continuation.finish(throwing:) bilan xato yuboriladi va for try await loop to'xtaydi. Bu tarmoq ulanishi uzilishi, sensor xatolari kabi holatlar uchun ideal.
// ═══════════════════════════════════════
// THROWING STREAM — xato tashlashi mumkin
// ═══════════════════════════════════════
enum StreamXatosi: Error {
case uzildi
}
func tarmoqOqimi() -> AsyncThrowingStream<String, Error> {
AsyncThrowingStream { continuation in
Task {
for i in 1...10 {
try? await Task.sleep(for: .seconds(1))
// 70% ehtimolda muvaffaqiyat
if Bool.random() && i > 5 {
// Xato bilan tugatish
continuation.finish(throwing: StreamXatosi.uzildi)
return
}
continuation.yield("Xabar #\(i)")
}
continuation.finish()
}
}
}
// for TRY await — xatoni ushlash
Task {
do {
for try await xabar in tarmoqOqimi() {
print(xabar)
}
print("Muvaffaqiyatli tugadi")
} catch {
print("Stream xato bilan tugadi: \(error)")
}
}
NotificationCenter bilan AsyncSequence
NotificationCenter.default.notifications(named:) — bildirishnomalarni asinxron kuzatish uchun tayyor AsyncSequence. Ilgari addObserver va removeObserver bilan ishlash kerak edi. Endi for await bilan har bir bildirishnomani avtomatik qabul qilish mumkin.
// ═══════════════════════════════════════
// NOTIFICATION — asinxron kuzatish
// ═══════════════════════════════════════
import UIKit
func klaviaturaniKuzatish() async {
let notifications = NotificationCenter.default.notifications(
named: UIResponder.keyboardDidShowNotification
)
// for await — har safar klaviatura chiqganda ishlaydi
for await notification in notifications {
if let frame = notification.userInfo?[
UIResponder.keyboardFrameEndUserInfoKey
] as? CGRect {
print("Klaviatura balandligi: \(frame.height)")
}
}
}
🎯 Topshiriq
AsyncStream<String> yarating — har 1 soniyada "Xabar #N" yuborsin, 10 ta xabardan keyin finish(). for await bilan o'qing. Keyin AsyncThrowingStream yarating — 5-xabarda xato tashlasin. do-try-catch bilan ushlang.