What is AsyncSequence
์ฉ๋์ด ์ข ํฐ csv ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋๋ค๊ณ ํ์. ๋ง์ฝ ํด๋น ํ์ผ์ ๋ชจ๋ ๋ฐ์ ๋ค์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ค๊ณ ํ๋ค๋ฉด, ์ค๋ ์๊ฐ ๋ค์๋ ๊ฐ๋ฅํ ๊ฒ์ด๋ค. ์ฌ๊ธฐ์ asyncSequence
๋ฅผ ์ฌ์ฉํ๋ฉด ๊ต์ฅํ ๋ฐ์์ฑ์๋ ๊ฒฐ๊ณผ๋ฅผ ๋ผ ์ ์๋ค.
struct QuakesTool {
static func main() async throws {
let endpointURL = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.csv")!
// header line ์คํตํ๊ณ ๋ผ์ธ ํ๋์ฉ ์ํ
// ๋๋ฉด์ ์ง๋, ์๊ฐ, ์๊ฒฝ๋ ์ถ์ถ
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), time: \(time), latitude: \(latitude), longitude: \(longitude)")
}
}
}
endpointURL.lines
๋ URL
์ ์๋ property์ด๋ค. AsyncLineSequence<URL.AsyncBytes>
ํ์
์ผ๋ก ๋์ด ์์ผ๋ฉฐ, ๋น๋๊ธฐ์ ์ผ๋ก ๋์ํ๋ค line์ ํด๋นํ๋ byte๊ฐ ๋ชจ๋ ๋ค์ด๋ก๋๋๋ฉด ์์ loop์์ ์ฝ๋๊ฐ ๋์ํ๋ค.
How it works
for quake in quakes {
if quake.magnitude > 3 {
displaySignificantEarthquake(queke)
}
}
์ฐ๋ฆฌ๊ฐ ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉํ๋ for loop์ ์ด๋ป๊ฒ ์ปดํ์ผ๋ฌ๊ฐ ๋ฐ์๋ค์ผ๊น?
var iterator = quakes.makeIterator()
while let quake = iterator.next() {
if quake.magnitude > 3 {
displaySignificantEarthquake(queke)
}
}
์ด๋ ๊ฒ iterator๋ฅผ ํตํด ๋ค์ ์์๋ฅผ ๋ฐ์ ์ฒ๋ฆฌํ๋ค. ๋ค์ ์์๊ฐ ์์ ๋๋ nil์ ๋์ณ while ๋ฃจํ๋ฅผ ์ข ๋ฃํ ์ ์๋ค. ์ด๋ ์ ํ์ ์ธ Iterator ํจํด์ด๋ค.
์ดํฐ๋ ์ดํฐ ํจํด(iterator pattern): ์ปฌ๋ ์ ๊ตฌํ ๋ฐฉ๋ฒ์ ๋ ธ์ถ์ํค์ง ์์ผ๋ฉด์๋ ๊ทธ ์งํฉ์ฒด ์์ ๋ค์ด์๋ ๋ชจ๋ ํญ๋ชฉ์ ์ ๊ทผํ ์ ์๋ ๋ฐฉ๋ฒ์ ์ ๊ณต
๊ทธ๋ผ for await in
syntax๋ ๋ฌด์์ด ๋ฌ๋ผ์ง๋ ๊ฒ์ผ๊น?
var iterator = quakes.makeAsyncIterator()
while let quake = await iterator.next() {
if quake.magnitude > 3 {
displaySignificantEarthquake(queke)
}
}
do {
for try await quake in quakeDownload {
if quake.depth > 5 { continue }
if quake.location == nil { break }
...
}
} catch {
}
์ด๋ ๊ฒ! ๋ค์ next์ ๋ํด ๋๊ธฐํ๋ ๊ฒ์ผ๋ก๋ง ๋ณ๊ฒฝ๋์๋ค. for await in
syntax๋ ๊ธฐ์กด for loop์์ ์ฌ์ฉํ๋ continue
, break
๋ฑ์ ๋์ผํ๊ฒ ์ฌ์ฉ๊ฐ๋ฅํ๋ค. ๋ํ Error handling๋ ๊ฐ๋ฅํ๋ค.
Encapsulation
์ด์ ๊ธ์์ ์ค์ ๋ก async
ํจ์๋ฅผ ์คํํ๊ธฐ ์ํด์๋ Task
๋ฅผ ๋ง๋ค์ด์ผ ํ๋ค๊ณ ํ๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก Async sequence๋ Task
์์ ์ ์ํ์ฌ ์บก์ํํ์ฌ ๊ด๋ฆฌํ ์ ์๋ค.
let iteration1 = Task {
for await quake in quakes {
if quake.magnitude > 3 {
displaySignificantEarthquake(queke)
}
}
}
let iteration2 = Task {
do {
for try await quake in quakeDownload {
if quake.depth > 5 { continue }
if quake.location == nil { break }
...
}
} catch {
}
}
iteration1.cancel()
iteration2.cancel()
Usage and APIs
์ฌ๊ธฐ์๋ ๊ฐ๋ตํ๊ฒ ์๊ฐํ๊ณ ๋์ด๊ฐ๋๋ก ํ๊ฒ ๋ค. ์ด๋ค ๊ฒ๋ค์ ํ ์ ์๋์ง๋ง ์์๋ณด์.
FileHandle
์ ํตํ Bytes ์ฝ๊ธฐ๋ฅผ ๋ผ์ธ๋ณ๋ก ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์๋ค.URL
์ผ๋ก๋ถํฐ line์ ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์๋ค. (๋งจ ์์์ ๋ณธ ์์: local, remote ์๊ด ์์)- Notification ์ฌ์ฉ..
ํด๋น ๋ถ๋ถ์ ์ง๊ธ ์๋ฟ์ง ์์, ์ถํ์ ์์์ ๋ค์ ๋ณด๋ ๊ฒ์ผ๋ก ํ๊ฒ ๋ค.
Custom AsyncSequence
๋ฌธ์๋ฅผ ์ฝ๋ค๋ณด๋, AsyncSequence
๊ฐ Protocol์ด๋ผ ์ด๋ฅผ ์ฑํํ๋ฉด ๋ ๋ฏํ์ฌ ํด๋ณธ๋ค.
Sequence
Array, Dictionary, Set ๋ฑ์ ๋ชจ๋ Sequence์ด๋ค. ๋จผ์ , ์ด Sequence
Protocol๋ก customํ๊ฒ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์์๋ณด์.
struct CustomSequence: Sequence { // Not working
}
๋จ์ํ๊ฒ Sequence Protocol์ ์ฑํํ๋ ๋ฐฉ๋ฒ์ผ๋ก๋ ์ด๋ฅผ ๋ง๋ค ์ ์๋ค. ์ด์ ๋ Sequence
Protocol์ด ํ์์ ์ผ๋ก ๊ฐ์ ธ์ผ ํ๋ method๊ฐ ์๊ธฐ ๋๋ฌธ์ด๋ค.
public protocol Sequence {
/// A type representing the sequence's elements.
associatedtype Element where Self.Element == Self.Iterator.Element
/// A type that provides the sequence's iteration interface and
/// encapsulates its iteration state.
associatedtype Iterator : IteratorProtocol
/// Returns an iterator over the elements of this sequence.
func makeIterator() -> Self.Iterator โ
}
Iterator๋ฅผ ๋ง๋ค๊ธฐ ์ํด์๋ IteratorProtocol
์ ์ค์ํ๋ ํ์
์ ๋ง๋ค์ด์ผ ํ๋ค.
struct CustomIterator: IteratorProtocol {
typealias Element = Int
private var current: Int = 0
mutating func next() -> Int? {
self.current += 1
return self.current
}
}
struct CustomSequence: Sequence {
func makeIterator() -> some IteratorProtocol {
return CustomIterator()
}
}
let sequence = CustomSequence()
for i in sequence {
print(i)
} // ๋ฌดํํ ์ซ์๊ฐ ๋์ด๋๋ฉฐ ์ถ๋ ฅ
์ด๋ฐ์์ผ๋ก ๋ง๋ค ์ ์๋ค. ๋ง์ฝ ์ค๊ฐ์ ๊ทธ๋ง๋๊ณ ์ถ๋ค๋ฉด if
๋ฌธ ์์์ break
์ ํด์ฃผ๋ ๋ฐฉํฅ์ด ์๊ฒ ๋ค. ์ค์ ๊ตฌํ์ด ์ด๋ฐ์์ผ๋ก ๋์ด ์๊ธฐ ๋๋ฌธ์, ์์์ ์ฐ๋ฆฌ๊ฐ for in
loop๋ฅผ ์ฌ์ฉํ์ ๋ compiler๊ฐ iterator
๋ฅผ ์์ฑํด์ฃผ๋ ๋ฐฉ์์ผ๋ก ๋์๊ฐ๋ ๊ฒ์ด๋ค.
๋ค๋ง, ์ฌ๊ธฐ์ ํน์ ํ์
์ IteratorProtocol
์ ๋์์ ์ฑํํ ๊ฒฝ์ฐ Iterator class๋ฅผ ๋ฐ๋ก ๋ง๋ค์ด์ฃผ์ง ์์๋ ๋๋ค. ์ฆ, ํ์
์์ฒด๊ฐ Iterator๋ก ๋์ํ๋ค.
struct CustomSequence: Sequence, IteratorProtocol {
typealias Element = Int
private var current: Int = 0
func makeIterator() -> Element? {
self.current += 1
return current
}
}
AsyncSequence
๊ธฐ๋ณธ์ ์ผ๋ก AsyncSequence
๋ Protocol์ด๊ธฐ ๋๋ฌธ์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํ๋ฉด ๋๊ฒ ๋ค.
struct CustomSequence: AsyncSequence, AsyncIteratorProtocol {
typealias Element = Int
private var current: Int = 1
mutating func next() โ
async โ
throws -> Int? {
if self.current == 10 {
return nil
}
self.current += 1
return current
}
func makeAsyncIterator() -> CustomSequence { โ
return self
}
}
Task {
let sequence = CustomSequence()
for try await number in sequence {
print(number)
}
}
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9
// 10
์ฌ๊ธฐ์ ๋ณ๊ฒฝ๋๋ ๊ฒ์ Sequence
๊ฐ AsyncSequence
๋ก, IteratorProtocol
์ด AsyncIteratorProtocol
๋ก ๋ณํํ๋ค๋ ์ ์ด๋ค. ๊ทธ๋ฆฌ๊ณ makeAsyncIterator()
๋ผ๋ ํจ์๋ฅผ ์ถ๊ฐ๋ก ๊ตฌํํด์ฃผ์ด์ผ ํ๋ค. Sequence
์ ๊ฒฝ์ฐ์๋ ์์์ง๋ง, ์ด๊ฒฝ์ฐ๋ ๋ชจ๋ ๊ตฌํํด์ฃผ์ด์ผ ํ๋ค.
๊ทธ๋ฆฌ๊ณ , next()
ํจ์์ throws
, async
๊ฐ ์ถ๊ฐ๋์๋ค. ๋ด๋ถ ๊ตฌํ์ด ์ด๋ ๊ธฐ ๋๋ฌธ์, for (try) await in
์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ.
๊ทธ๋ฐ๋ฐ, ์๊น for await in
์ผ๋ก๋ง ์ฌ์ฉํ์ง ์์์๋? throws
๊ฐ ๋ถ๊ฒ ๋๋ฉด for try await in
์ผ๋ก ๋ฌด์กฐ๊ฑด์ ์ผ๋ก ์ฌ์ฉํด์ผ ํ๋ ๊ฒ ์๋๊ฐ? ๊ทธ๋์ ์ด throws
๋ฅผ ์ ๊ฑฐํ ์ ์๋ค. ๊ทธ๋ ๊ฒ ๋๋ฉด ์์์ ๋ณธ ๊ฒ์ฒ๋ผ for await in
์ผ๋ก ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค!
์ผ๋จ ์์ ์ฝ๋๋ฅผ ๋๋ฆฌ๋ฉด 10๊น์ง๋ง ๊ฒฐ๊ณผ๊ฐ ๋์ค๊ณ ์ข
๋ฃ๋๋ค. sequence์์ ๊ฒฐ๊ณผ๋ฅผ ์ข
๋ฃํ๊ณ ์ถ๋ค๋ฉด nil
์ ๋ฆฌํดํ๋ฉด ๋๋ค.
Summary
AsyncSequence
๋ step๋ณ๋ก ๋ฐ์ ์ ์๋ ๊ฐ์ ์ ๊ณต + ๋น๋๊ธฐ์ฑ ์ถ๊ฐํ Protocol์ด๋ค.- ํด๋น protocol์ ์ค์ํ ์น๊ตฌ๋ค์ ์์ ๊ฐ์ ํ์์ผ๋ก
for (try) await in
syntax๋ฅผ ์ฌ์ฉํ ์ ์๋ค. - ๋น๋๊ธฐ์ ์ผ๋ก ๋์ํ๊ธฐ ๋๋ฌธ์
await
์ ํจ๊ป ์ฌ์ฉํ๋ค. - ๋ํ ๋น๋๊ธฐ์ ์ผ๋ก ๊ฐ์ ๊ฐ์ ธ์ค๊ธฐ ๋๋ฌธ์, ์คํจํ ๊ฐ๋ฅ์ฑ๋ ์๋ค. ๊ทธ๋์
try
ํค์๋๋ฅผ ์ฌ์ฉํ๋ค. - ๋ค์ ์กฐ๊ฑด(์คํจํ๊ฑฐ๋, ๋ชจ๋ ์ํํ๊ฑฐ๋)์ธ ๊ฒฝ์ฐ loop๋ ๋๋๋ค.
- Custom Async Sequence๋ ๋ง๋ค ์ ์๋ค. ๋ง๋๋ ๋ฐฉ๋ฒ์ Custom Sequence๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ๊ณผ ์๋นํ ์ ์ฌํ๋ค.