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)
}
}