ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Swift] Understanding Swift Concurrency’s AsyncStream
    Swift 2023. 8. 17. 09:25

    ์ด์ „ ๊ธ€์—์„œ ๊ธฐ์กด์˜ ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ async/await์„ ํ™œ์šฉํ•˜๋Š” Swift์˜ ์ƒˆ๋กœ์šด ๋™์‹œ์„ฑ ์‹œ์Šคํ…œ์œผ๋กœ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์„ค๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์„ค๋ช…ํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์ฝ”๋“œ๊ฐ€ ๋‹จ์ผ ๊ฐ’์œผ๋กœ ๋ชจ๋ธ๋งํ•  ์ˆ˜ ์žˆ๋Š” ๋‹จ์ผ ๊ฒฐ๊ณผ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

     

    ๋‹ค์šด๋กœ๋“œ ์ง„ํ–‰๋ฅ , ์‚ฌ์šฉ์ž์˜ ํ˜„์žฌ ์œ„์น˜์™€ ๊ฐ™์ด ์‹œ๊ฐ„์— ๋”ฐ๋ผ ์—ฌ๋Ÿฌ ๊ฐ’์„ ์ œ๊ณตํ•˜๋Š” ๊ฒฝ์šฐ, ๋น„๋™๊ธฐ for ๋ฃจํ”„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ˜๋ณตํ•  ์ˆ˜ ์žˆ๋Š” AsyncSequence ๊ฐ์ฒด๋กœ ๋ชจ๋ธ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ๊ธฐ๋ณธ์ ์ธ ์˜ˆ์ œ๋กœ URL์˜ lines ์†์„ฑ์„ ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    let url = URL(string: "<https://donnywals.com>")!
    
    for try await line in url.lines {
        // use line
    }
    

    ๊ทธ๋ ‡๋‹ค๋ฉด ์ปค์Šคํ…€ ๋น„๋™๊ธฐ ์‹œํ€€์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ผ๊นŒ์š”?

    AsyncSequence ํ”„๋กœํ† ์ฝœ์„ ๊ตฌํ˜„ํ•˜๊ณ  AsyncIterator์—์„œ ๋นŒ๋“œํ•˜๋Š” ๊ฒƒ์€ ์ง€๋ฃจํ•˜๊ณ  ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ๋‹คํ–‰ํžˆ๋„ ์ด๋Ÿฐ ์ž‘์—…์„ ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

    ์ด ๊ธ€์—์„œ๋Š” Swift์˜ AsyncStream์„ ํ™œ์šฉํ•˜์—ฌ ํ•„์š”ํ•  ๋•Œ๋งˆ๋‹ค ๊ฐ’์„ ์ƒ์„ฑํ•˜๋Š” ์‚ฌ์šฉ์ž ์ •์˜ async ์‹œํ€€์Šค๋ฅผ ๋นŒ๋“œํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

     

    ๊ฐ„๋‹จํ•œ ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ (async stream) ์ƒ์„ฑํ•˜๊ธฐ

    ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์€ ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•˜๋Š” ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€AsyncStream(unfolding:) ์ƒ์„ฑ์ž๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

    let stream = AsyncStream(unfolding: { 
    	return Int.random(in: 0..<Int.max)
    })
    

    ๋ฌผ๋ก  ์ด ์˜ˆ์ œ๊ฐ€ ์œ ์šฉํ•˜์ง„ ์•Š์ง€๋งŒ, AsyncStream(unfolding:)์˜ ๊ฐœ๋…์— ์–ผ๋งˆ๋‚˜ ๊ฐ„๋‹จํ•œ์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ์šฐ๋ฆฌ๋Š” AsyncStream์„ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•  ๊ฐ’์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. unfolding์— ์ „๋‹ฌ๋˜๋Š” ํด๋กœ์ €๋Š” ๋น„๋™๊ธฐ์ด๋ฏ€๋กœ ํด๋กœ์ € ๋‚ด์—์„œ ๋น„๋™๊ธฐ ์—ฐ์‚ฐ์„ ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ŠคํŠธ๋ฆผ์— ๋Œ€ํ•œ ๊ฐ’์„ ์ƒ์„ฑํ•˜๊ธฐ ์‹œ์ž‘ํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋  ๋–„๋งˆ๋‹ค unfolding ํด๋กœ์ €๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ๋Š” ํด๋กœ์ €๊ฐ€ ํ˜ธ์ถœ๋˜์–ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ ๋‹ค์Œ ํด๋กœ์ €๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์€ for ๋ฃจํ”„๊ฐ€ ์ทจ์†Œ๋˜๊ฑฐ๋‚˜ ๋น„๋™๊ธฐ for loop๋ฅผ ํฌํ•จํ•˜๋Š” ์ž‘์—…์ด ์ทจ์†Œ๋˜๊ฑฐ๋‚˜, unfolding ํด๋กœ์ €์—์„œ nil์„ ๋ฐ˜ํ™˜ํ•  ๋•Œ๊นŒ์ง€ ๊ณ„์†๋ฉ๋‹ˆ๋‹ค.

     

    AsyncStream(unfolding:)์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ’ ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋งค์šฐ ํŽธ๋ฆฌํ•˜์ง€๋งŒ ํŠนํžˆ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

    • ๊ฐ’์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ
    • API๋ฅผ ๋ธŒ๋ฆฟ์ง•ํ•˜๋Š” ๋™์•ˆ ๋ฐฑ ํ”„๋ ˆ์…”๋ฅผ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ

    ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ๊ธฐ์กด API๋ฅผ ๋ธŒ๋ฆฌ์ง•ํ•˜๊ฑฐ๋‚˜ ์ฝœ๋ฐฑ์„ ํ™œ์šฉํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ์ „๋‹ฌํ•˜๋Š” API์˜ ๊ฒฝ์šฐ, AsyncStream(unfolding:)์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

    AsyncStream(unfolding:)์€ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜๊ณ  ์˜ค๋ฅ˜๊ฐ€ ์ ๊ฒŒ ๋ฐœ์ƒํ•˜๋Š” ๋ฐฉ๋ฒ•์ด์ง€๋งŒ, ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ Swift Concurrency๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐ ๊ฐ€์žฅ ์ œํ•œ์ ์ด๋ฉฐ ์ ํ•ฉํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.

    AsyncStream์— ๋Œ€ํ•œ continuation API์—์„œ ๋” ๋งŽ์€ ์œ ์—ฐ์„ฑ์„ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    continuation์„ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ (async stream) ์ƒ์„ฑํ•˜๊ธฐ

    ๋น„๋™๊ธฐ ํด๋กœ์ €๊ฐ€ ์ž์ฒด ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•˜๋Š” ๋ฐ ์ ํ•ฉํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ, continuation ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ๋ฐฉ์‹์ด ํ›จ์”ฌ ๋” ๋‚˜์€ ํ•ด๊ฒฐ์ฑ…์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. continuation์„ ์‚ฌ์šฉํ•˜๋ฉด ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ ๊ฐ์ฒด๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ๊ฐ’์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋  ๋•Œ๋งˆ๋‹ค ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์„ ํ†ตํ•ด ๊ฐ’์„ ์ „์†กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

    ๋‹ค์Œ๊ณผ ๊ฐ™์ด AsyncStream(build:) ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•ด ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    let stream2 = AsyncStream { continuation in
    	continuation.yield(Int.random(in: 0..<Int.max))
    }
    

    ์œ„์˜ ์˜ˆ์ œ๋Š” ํ•˜๋‚˜์˜ ์ •์ˆ˜ ๊ฐ’์„ ์ƒ์„ฑํ•˜๋Š” ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฐ’์€ continuation์—์„œ yield๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ „์†กํ•  ๊ฐ’์ด ์žˆ์„ ๋•Œ๋งˆ๋‹ค continuation์—์„œ yield๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

     

    ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ๊ธฐ๋ฐ˜ API๋ฅผ ๋ž˜ํ•‘ํ•˜๋Š” AsyncStream์„ ์ƒ์„ฑํ•  ๊ฒฝ์šฐ, ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ๊ฐ์ฒด์— continuation์„ ๋ณด์œ  (์œ ์ง€)ํ•˜๊ณ  ๊ด€๋ จ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค yield๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

    ์˜ˆ๋ฅผ ๋“ค์–ด, ์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž์˜ ์œ„์น˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๋•Œ๋งˆ๋‹ค CLLocationManagerDelegate ๋‚ด์—์„œ contiunation.yield๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    class AsyncLocationStream: NSObject, CLLocationManagerDelegate {
        lazy var stream: AsyncStream<CLLocation> = {
            AsyncStream { (continuation: AsyncStream<CLLocation>.Continuation) -> Void in
                self.continuation = continuation
            }
        }()
        var continuation: AsyncStream<CLLocation>.Continuation?
    
        func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    
            for location in locations {
                continuation?.yield(location)
            }
        }
    }
    

    ์œ„์˜ ์˜ˆ์ œ๋Š” ์‚ฌ์šฉ์ž ์œ„์น˜์˜ ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ๋งค์šฐ ๊ธฐ๋ณธ์ ์ธ ์‹œ์ž‘์ ์ž…๋‹ˆ๋‹ค. ์œ„์น˜ ๊ด€์ฐฐ์„ ์ทจ์†Œ ๋ฐ ์‹œ์ž‘ํ•˜๊ฑฐ๋‚˜ ์œ„์น˜ ๊ถŒํ•œ์„ ์š”์ฒญํ•˜๋Š” ๋“ฑ ์™„์ „ํžˆ ๊ณ ๋ คํ•˜์ง€ ์•Š์€ ๋ช‡ ๊ฐ€์ง€ ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

    ํ•˜์ง€๋งŒ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด ์˜ˆ์ œ๋Š” ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์„ ์‹คํ—˜ํ•˜๊ธฐ ์œ„ํ•œ ์ข‹์€ ์ถœ๋ฐœ์ ์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์˜ ์†Œ๋น„์ž๊ฐ€ ๋‹ค์Œ ๊ฐ’์„ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณด๋‚ด๊ธฐ ์ „์— ์ด์ „ ๊ฐ’์„ ์™„์ „ํžˆ ์†Œ๋น„ํ•  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  ์ „์†กํ•˜๋Š” ๋ชจ๋“  ๊ฐ’์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์—์„œ ๋ฒ„ํผ๋ง๋˜๋ฉฐ, ์ด๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์›ํ•˜๋Š” ๊ฐ’์ผ ์ˆ˜๋„ ์žˆ๊ณ  ์•„๋‹ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

     

    ์ฆ‰, ์‹ค์ œ๋กœ ์†Œ๋น„์ž๊ฐ€ ๊ฐ’์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์†๋„๋ณด๋‹ค ๋” ๋น ๋ฅธ ์†๋„๋กœ ๊ฐ’์„ ๋ณด๋‚ผ ๊ฒฝ์šฐ, ๋ฒ„ํผ๊ฐ€ ๊ฐ€๋“ ์ฐจ๊ฒŒ ๋˜๋ฉฐ ์†Œ๋น„ํ•˜๋Š” for ๋ฃจํ”„์— ๊ฐ’์ด ์ง€์—ฐ๋˜์–ด ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ •ํ™•ํžˆ ํ•„์š”ํ•œ ๊ฒƒ์ผ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์ „์†กํ•˜๋Š” ๊ฐ’์ด ๋‹ค์†Œ ์‹œ๊ฐ„์— ๋ฏผ๊ฐํ•˜๊ณ  ์ผ์‹œ์ ์ธ ๊ฒฝ์šฐ, ์†Œ๋น„ํ•˜๋Š” for ๋ฃจํ”„๊ฐ€ ๊ฐ’์„ ๋ฐ›์„ ์ค€๋น„๊ฐ€ ๋˜์ง€ ์•Š์•˜์„ ๋•Œ ๊ฐ’์„ ๋ฒ„๋ฆฌ๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

    ์˜ˆ๋ฅผ ๋“ค์–ด ์˜ค๋ž˜๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•ด 1๊ฐœ ์ด์ƒ์˜ ์œ„์น˜๋ฅผ ๋ณด์œ ํ•˜์ง€ ์•Š๊ณ  ๋งˆ์ง€๋ง‰์œผ๋กœ ์•Œ๋ ค์ง„ ์œ„์น˜๋งŒ ๋ฒ„ํผ๋งํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฒ„ํผ๋ง ์ •์ฑ…์„ ์„ค์ •ํ•˜๋ฉด ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

    lazy var stream: AsyncStream<CLLocation> = {
        AsyncStream(bufferingPolicy: .bufferingNewest(1)) { (continuation: AsyncStream<CLLocation>.Continuation) -> Void in
            self.continuation = continuation
        }
    }()

    ์ด ์ฝ”๋“œ๋Š” ๋ฒ„ํผ๋ง ์ •์ฑ…์œผ๋กœ .bufferingNewest(1)๋ฅผ AsyncStream์— ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, for ๋ฃจํ”„๊ฐ€ ํ•ญ๋ชฉ์„ ์ถฉ๋ถ„ํžˆ ๋น ๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ ๋‹จ์ผ ๊ฐ’๋งŒ ๋ฒ„ํผ๋งํ•˜๊ณ , ์ตœ์‹  ์œ„์น˜๋งŒ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์ด์ „ ๊ฐ’์€ ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค.

    ์ŠคํŠธ๋ฆผ์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ข…๋ฃŒ๋˜๋ฉด continuation์— finish()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ฐ’ ์ŠคํŠธ๋ฆผ์„ ์ข…๋ฃŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

    ์ŠคํŠธ๋ฆผ์ด ์—๋Ÿฌ์™€ ํ•จ๊ป˜ ์‹คํŒจํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ AsyncStream ๋Œ€์‹ ์— AsyncThrowingStream์„ ์ƒ์„ฑํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฃผ์š” ์ฐจ์ด์ ์€ ์—๋Ÿฌ๋ฅผ throwํ•˜๋Š” ์ŠคํŠธ๋ฆผ์˜ ์†Œ๋น„์ž๋Š” try await ๋Œ€์‹ ์— ๋‹จ์ˆœํžˆ await๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒˆ ๊ฐ’์„ ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ŠคํŠธ๋ฆผ์ด ์—๋Ÿฌ๋ฅผ throwํ•˜๊ฒŒ ๋งŒ๋“ค๋ ค๋ฉด continuation์—์„œ finish(throwing:)๋ฅผ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ Result ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ yield(with:)๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๊ธฐ๋ณธ ์‚ฌํ•ญ์€ ํŠน๋ณ„ํžˆ ๋ณต์žกํ•˜์ง€๋Š” ์•Š์ง€๋งŒ, ์šฐ๋ฆฌ๊ฐ€ ์ƒ์„ฑํ•˜๋Š” ๊ฐ์ฒด์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ์–ด๋–ป๊ฒŒ ๊ด€๋ฆฌํ• ์ง€ ์‹ ์ค‘ํ•˜๊ฒŒ ์ƒ๊ฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ๊ธฐ์กด ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ๊ธฐ๋ฐ˜ ์ฝ”๋“œ๋ฅผ ๋ธŒ๋ฆฌ์ง•ํ•  ๋•Œ continuation์ด ์ŠคํŠธ๋ฆผ๋ณด๋‹ค ์˜ค๋ž˜ ์œ ์ง€๋˜์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    ์ŠคํŠธ๋ฆผ ์ˆ˜๋ช…์ฃผ๊ธฐ ๊ด€๋ฆฌํ•˜๊ธฐ

    ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์ด ์ข…๋ฃŒ๋˜๋Š” ๋ฐฉ๋ฒ•์—๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ 2๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

     

    ์ฒซ์งธ, ๋” ์ด์ƒ ๊ฐ’์ด ์ƒ์„ฑ๋˜์ง€ ์•Š์•„ ์ŠคํŠธ๋ฆผ์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊ฐ’ ์ƒ์„ฑ์„ ์ข…๋ฃŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. continuation์— finish๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๋™์‹œ์— ์ˆ˜ํ–‰ํ•ด์•ผ ํ•  ๋ชจ๋“  ์ •๋ฆฌ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์˜๋„์น˜ ์•Š๊ฒŒ ๋” ์ด์ƒ continuation์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก continuation์„ nil๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

    ๋˜๋Š”, ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์„ ์‹คํ–‰ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์ž‘์—…์ด ์ทจ์†Œ๋˜์–ด ์ŠคํŠธ๋ฆผ์ด ์ข…๋ฃŒ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์„ ๊ณ ๋ คํ•˜์„ธ์š”.

    let locations = AsyncLocationStream()
    
    let task = Task {
        for await location in locations.stream {
            print(location)
        }
    }
    
    task.cancel()

    ์œ„์™€ ๊ฐ™์€ ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•˜๋ฉด ์ด๋ฏธ ์™„๋ฃŒ๋œ ์ŠคํŠธ๋ฆผ์— ๊ฐ’์„ ๋ณด๋‚ด์ง€ ์•Š๋„๋ก continuation์— yield๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ข…๋ฃŒ๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ๋Œ€์‘ํ•˜๊ธฐ ์œ„ํ•ด continuation์— onTermination ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

    self.continuation?.onTermination = { result in
        print(result)
        self.continuation = nil
    }
    

    ๊ฐ€๋Šฅํ•˜๋ฉด ์ด ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์„ ์ฒ˜์Œ ์ƒ์„ฑํ•  ๋•Œ ์ฆ‰์‹œ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

    ๋˜ํ•œ ์ŠคํŠธ๋ฆผ์ด ์ทจ์†Œ๋˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚œ ๊ฒฝ์šฐ์—๋„ ๋ฃจํ”„๋ฅผ ํƒˆ์ถœํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ž‘์—…์ด ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์ด ๊ฒฝ์šฐ ์ŠคํŠธ๋ฆผ์ด ์ข…๋ฃŒ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ฏ€๋กœ, ๋ฃจํ”„๋ฅผ ํƒˆ์ถœํ•˜์—ฌ ์ŠคํŠธ๋ฆผ์„ ์ข…๋ฃŒํ•˜๋ ค๋ฉด ์ด ์ ์„ ์ง์ ‘ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

     

    ๊ธ€์˜ ์ž‘์„ฑ์ž๋Š” ๊ฐœ์ธ์ ์œผ๋กœ ์ŠคํŠธ๋ฆผ์„ ๊ฐ€์žฅ ์‰ฝ๊ฒŒ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ์ŠคํŠธ๋ฆผ์„ ์ƒ์„ฑํ•˜๋Š” ๊ฐ์ฒด์— ๋น„๋™๊ธฐ ๋ฃจํ”„์—์„œ ๋ฒ—์–ด๋‚˜๋Š” ๋Œ€์‹  ์ŠคํŠธ๋ฆผ์„ ์ทจ์†Œํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ •๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ  ์•„๋ฌด๋„ ์ˆ˜์‹ ํ•˜์ง€ ์•Š๋Š”๋ฐ๋„ ๊ฐ’์„ ์ „์†กํ•˜๋Š” ์ŠคํŠธ๋ฆผ์„ ๋งŒ๋“ค์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ๋˜ํ•œ ์•ž์„œ ์„ค๋ช…ํ•œ ํŒจํ„ด์€ ํ•œ ๋ช…์˜ ์†Œ๋น„์ž๊ฐ€ ์œ„์น˜ ์ŠคํŠธ๋ฆผ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ž‘๋™ํ•œ๋‹ค๋Š” ์ ์„ ๋ช…์‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ๋น„๋™๊ธฐ ์‹œํ€€์Šค์—๋Š” ๋ฐ˜๋ณต์„ ์—ฌ๋Ÿฌ ๋ฃจํ”„์™€ ๊ณต์œ ํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— Swift Concurrency์—์„œ๋Š” ๋‹จ์ผ ์ŠคํŠธ๋ฆผ์„ ๋ฐ˜๋ณตํ•˜๋Š” ๋ฃจํ”„์— ๋Œ€ํ•ด ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฃจํ”„๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

    In Summary

    ์ด ํฌ์ŠคํŒ…์—์„œ๋Š” ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ๊ณผ ์ž์‹ ๋งŒ์˜ ๋น„๋™๊ธฐ ์‹œํ€€์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋งŽ์€ ๊ฒƒ์„ ๋ฐฐ์› ์Šต๋‹ˆ๋‹ค. ๋จผ์ €, ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์„ ๋นŒ๋“œํ•˜๋Š” ์–ธํด๋”ฉ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ดํŽด๋ณด๊ณ  ์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ ๋น„๊ต์  ๊ฐ„๋‹จํ•˜์ง€๋งŒ ๊ธฐ์กด ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ๋˜๋Š” ์ฝœ๋ฐฑ ๊ธฐ๋ฐ˜ API๋ฅผ ์—ฐ๊ฒฐํ•ด์•ผ ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์—๊ฒŒ๋Š” ๊ทธ๋‹ค์ง€ ์œ ์šฉํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ฐฐ์› ์Šต๋‹ˆ๋‹ค.

    ์–ธํด๋”ฉ์— ๋Œ€ํ•ด ์ž ์‹œ ์‚ดํŽด๋ณธ ํ›„ ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ์— ๋Œ€ํ•œ ๋นŒ๋“œ ํด๋กœ์ €์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ ํ•„์š”ํ•  ๋•Œ ํ˜ธ์ถœํ•˜์—ฌ ๊ฐ’์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ์—ฐ์† ๊ฐ์ฒด๋ฅผ ํ™œ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋ฐฐ์› ์Šต๋‹ˆ๋‹ค.

    CLLocationManager๋ฅผ ๋น„๋™๊ธฐ ๋Œ€๊ธฐ ์ƒํƒœ๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฐ์ฒด์˜ ์•„์ฃผ ๊ธฐ์ดˆ์ ์ธ ์˜ˆ์ œ๋ฅผ ๋ณด์…จ๊ณ , ์ด๋ฏธ ์™„๋ฃŒ๋œ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๊ฐ’์„ ๋ณด๋‚ด์ง€ ์•Š๋„๋ก ์—ฐ์†์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋ฐฐ์› ์Šต๋‹ˆ๋‹ค.

     

     

    ์›๋ฌธ

    https://www.donnywals.com/understanding-swift-concurrencys-asyncstream/

    ๋Œ“๊ธ€

Designed by Tistory.