Section 7/131 menit

7. AsyncSequence & AsyncStream

7. AsyncSequence & AsyncStream

Teori: Data yang Datang Seiring Waktu

AsyncSequence adalah versi asinkron dari Sequence — cocok untuk data yang tidak tersedia sekaligus, tapi datang secara bertahap.

swift
Sequence (sync):  [1, 2, 3, 4, 5]          → tersedia langsung
AsyncSequence:     1 ... (delay) ... 2 ... (delay) ... 3    → tersedia bertahap

AsyncStream — Custom Sequence Sederhana

swift
// Timer sebagai AsyncStream
func timerStream(interval: TimeInterval) -> AsyncStream<Date> {
    AsyncStream { continuation in
        let timer = Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { _ in
            continuation.yield(Date())
        }

        continuation.onTermination = { _ in
            timer.invalidate()
        }
    }
}

// Penggunaan
Task {
    for await tick in timerStream(interval: 1.0) {
        print("Tick: \(tick)")

        if someCondition { break }
    }
}

AsyncThrowingStream — Stream yang Bisa Error

swift
// WebSocket messages sebagai AsyncThrowingStream
func webSocketMessages(url: URL) -> AsyncThrowingStream<String, Error> {
    AsyncThrowingStream { continuation in
        let task = URLSession.shared.webSocketTask(with: url)

        func receiveNext() {
            task.receive { result in
                switch result {
                case .success(let message):
                    switch message {
                    case .string(let text):
                        continuation.yield(text)
                    case .data(let data):
                        continuation.yield(String(data: data, encoding: .utf8) ?? "")
                    @unknown default:
                        break
                    }
                    receiveNext()  // terus mendengarkan pesan berikutnya

                case .failure(let error):
                    continuation.finish(throwing: error)
                }
            }
        }

        task.resume()
        receiveNext()

        continuation.onTermination = { _ in
            task.cancel(with: .goingAway, reason: nil)
        }
    }
}

// Penggunaan
Task {
    do {
        for try await message in webSocketMessages(url: wsURL) {
            handleMessage(message)
        }
    } catch {
        handleDisconnection(error)
    }
}

Transformasi AsyncSequence

swift
// filter, map, dll. tersedia di AsyncSequence
let highValueEvents = eventStream
    .filter { $0.value > 100 }
    .map { EventViewModel(event: $0) }

Task {
    for await event in highValueEvents {
        displayEvent(event)
    }
}