2021 Swift
Meet AsyncSequence
Iterating over a sequence of values over time is now as easy as writing a “for” loop. Find out how the new AsyncSequence protocol enables a natural, simple syntax for iterating over anything from notifications to bytes being streamed from a server. We’ll also show you how to adapt existing code to provide asynchronous sequences of your own. To get the most out of this session, we recommend first watching “Meet async/await in Swift.”
Watch at developer.apple.com ↗Code shown on screen · 14 snippets
QuakesTool
@main
struct QuakesTool {
static func main() async throws {
let endpointURL = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.csv")!
// skip the header line and iterate each one
// to extract the magnitude, time, latitude and longitude
for try await event in endpointURL.lines.dropFirst() {
let values = event.split(separator: ",")
let time = values[0]
let latitude = values[1]
let longitude = values[2]
let magnitude = values[4]
print("Magnitude \(magnitude) on \(time) at \(latitude) \(longitude)")
}
}
} Iterating a Sequence
for quake in quakes {
if quake.magnitude > 3 {
displaySignificantEarthquake(quake)
}
} How the compiler handles iteration
var iterator = quakes.makeIterator()
while let quake = iterator.next() {
if quake.magnitude > 3 {
displaySignificantEarthquake(quake)
}
} How the compiler handles asynchronous iteration
var iterator = quakes.makeAsyncIterator()
while let quake = await iterator.next() {
if quake.magnitude > 3 {
displaySignificantEarthquake(quake)
}
} Iterating an AsyncSequence
for await quake in quakes {
if quake.magnitude > 3 {
displaySignificantEarthquake(quake)
}
} Terminating iteration early by breaking
for await quake in quakes {
if quake.location == nil {
break
}
if quake.magnitude > 3 {
displaySignificantEarthquake(quake)
}
} Skipping values by continuing
for await quake in quakes {
if quake.depth > 5 {
continue
}
if quake.magnitude > 3 {
displaySignificantEarthquake(quake)
}
} AsyncSequence might throw
do {
for try await quake in quakeDownload {
...
}
} catch {
...
} Concurrently iterating inside an async task
let iteration1 = Task {
for await quake in quakes {
...
}
}
let iteration2 = Task {
do {
for try await quake in quakeDownload {
...
}
} catch {
...
}
}
//... later on
iteration1.cancel()
iteration2.cancel() Reading bytes from a FileHandle
for try await line in FileHandle.standardInput.bytes.lines {
...
} Reading lines from a URL
let url = URL(fileURLWithPath: "/tmp/somefile.txt")
for try await line in url.lines {
...
} Reading bytes from a URLSession
let (bytes, response) = try await URLSession.shared.bytes(from: url)
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 /* OK */
else {
throw MyNetworkingError.invalidServerResponse
}
for try await byte in bytes {
...
} Notifications
let center = NotificationCenter.default
let notification = await center.notifications(named: .NSPersistentStoreRemoteChange).first {
$0.userInfo[NSStoreUUIDKey] == storeUUID
} Using an AsyncStream
class QuakeMonitor {
var quakeHandler: (Quake) -> Void
func startMonitoring()
func stopMonitoring()
}
let quakes = AsyncStream(Quake.self) { continuation in
let monitor = QuakeMonitor()
monitor.quakeHandler = { quake in
continuation.yield(quake)
}
continuation.onTermination = { _ in
monitor.stopMonitoring()
}
monitor.startMonitoring()
}
let significantQuakes = quakes.filter { quake in
quake.magnitude > 3
}
for await quake in significantQuakes {
...
} Resources
Related sessions
-
13 min -
13 min -
10 min -
14 min -
38 min -
34 min -
28 min