What is AsyncSequence?
@main
struct QuakesTool {
static func main() async throws {
let endpointURL = URL(string: "<https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.csv>")!
// lines가 AsyncSequence
// 맨 위 헤더는 드롭
for try await event in endpointURL.lines.dropFirst() {
let value = event.split(separator: ",")
let time = values[0]
let latitude = values[1]
let longtitude = values[2]
let magnitude = values[4]
print("Magnitude \\(magnitude) on \\(time) at \\(latitude) \\(longtitude)")
}
}
}
// 이러한 for문이
for quake in quakes {
if quake.magnitude > 3 {
displaySignificantEarthquake(quake)
}
}
// 이렇게 바뀐다.
var iterator = quakes.makeIterator()
while let quake = iterator.next() {
if quake.magnitude > 3 {
displaySignificantEarthquake(quake)
}
}
// 이게
for await quake in quakes {
if quake.magnitude > 3 {
displaySignificantEarthquake(quake)
}
}
// 이렇게 바뀐다
var iterator = quakes.makeAsyncIterator()
while let quake = await iterator.next() {
if quake.magnitude > 3 {
displaySignificantEarthquake(quake)
}
}
for await quake in quakes {
if quake.location == nil {
break
}
if quake.magnitude > 3 {
displaySignificantEarthquake(quake)
}
}
for await quake in quakes {
if quake.depth > 5 {
continue
}
if quake.magnitude > 3 {
displaySignificantEarthquake(quake)
}
}
do {
for try await quake in quakeDownload {
...
}
} catch {
...
}
async {
for await quake in quakes {
...
}
}
async {
do {
for try await quake in quakeDownload {
...
}
} catch {
...
}
}
let iteration1 = async {
for await quake in quakes {
...
}
}
let iteration2 = async {
do {
for try await quake in quakeDownload {
...
}
} catch {
...
}
}
iteration1.cancel()
iteration2.cancel()
Usage and APIs
// FileHandle
public var bytes: AsyncBytes
for try await line in FileHandle.standardInput.bytes.lines {
}
// URL
public var resourcesBytes: AsyncBytes
public var lines: AsyncLineSequence<AsyncBytes>
let url = URL(fileURLWithPath: "/tmp/somefile.txt")
for try await line in url.lines {
}
func bytes(from: URL) async throws -> (AsyncBytes, URLResponse)
func bytes(from: URLReqeust) async throws -> (AsyncBytes, URLResponse)
let (bytes, response) = try await URLSesssion.shared.bytes(from: url)
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw MyNetworkingError.invalidServiceResponse
}
for try await byte in bytes {
}
public func notifications(named: Notification.Name, object: AnyObject) -> Notifications
let center = NotificationCenter.default
let notification = await center.notifications(named: .NSPersistentStoreRemoteChange).first {
$0.userInfo[NSStoreUUIDKey] == storeUUID
}
Adopting AsyncSequence
// 기존 패턴
class QuakeMonitor {
var quakeHandler: (Quake) -> Void
func startMonitoring()
func stopMonitoring()
}
let monitor = QuakeMonitor()
monitor.quakeHandler = { quake in
// ...
}
monitor.startMonitoring()
monitor.stopMonitoring()
// async로 변경
let quakes = AsyncStream(Quake.self) { continuation in
let monitor = QuakeMonitor()
monitor.quakeHandler = { quake in
continuation.yield(quake)
}
continuation.onTermination = { _ in
monitor.stopMonitoring()
}
monitor.startMonitoring()
}
// ASyncStream 생성자
public struct AsyncStream<Element>: AsyncSequence {
public init(
_ elementType: Element.Type = Element.self,
maxBufferedElements limit: Int = .max,
_ build: (Continuation) -> Void
)
}
// 에러를 던질 수 있는 AsyncStream
public struct AsyncThrowingStream<Element>: AsyncSequence {
public init(
_ elementType: Element.Type = Element.self,
maxBufferedElements limit: Int = .max,
_ build: (Continuation) -> Void
)
}