iOS/Swift Concurrency

AsyncStream

Hamp 2025. 5. 25. 17:11
반응형

👋 들어가기 전

이번 포스팅은 컨커런시에서 제공해주는 비동기 반복문에 사용되는 객체를

 

내가 직접 만들기 위한 여정을 알아보자.

 

비동기 반복문은 for awiat in ... 형태인데

여기서 ...에 들어가는 내용이 바로 AsyncStream이다.

 

또한 실제 동기 for문에서도 쓰이는 여러가지 collection들은 반복문들과 사용하기위해

Sequence + IteratorProtocol을 채택하고 있다.

 

비동기 반복문 역시도 AsyncSequence + AsyncIteratorProtocol을 채택해야한다.

 

차례대로 알아보자.

🏁 학습할 내용

  • AsyncSequence
  • AsyncIteratorProtocol
  • AsyncStream

🚂 AsyncSequence

먼저 알아볼 내용은 AsyncSequence 프로토콜이다.

 

AsyncSequence = Async(비동기) + Seqeunce

Sequence

시퀀스 프로토콜은 갇나히 말하면 Iterator(반복자)를 생성해내는 프로토콜이다.

struct CustomSequence: Sequence {
  func makeIterator() -> CustomIterator {

  }
}

 

정리하면 AsyncSequence는 비동기 반복자를 만들어내는 프로토콜이다.


♻️ AsyncIteratorProtocol

다음은 AsyncIteratorProtocol이다.

 

이 내용도 마찬가지로 2개로 분리할 수 있다.

AsyncIteratorProtocol = Async(비동기) + IteratorProtocol

IteratorProtocol

Sequence 프로토콜은 반복자를 생성해내는 프토토콜이면

IteratorProtocol은 그 반복자를 정의하는 프로토콜이다.

 

여기서 next함수의 리턴타입이 바로, 반복문이 뱉어내는 Element 타입의 옵셔널 형태이다.

struct CustomIterator: IteratorProtocol {
  func next() -> Int? {

  }
}

 

두 프로토콜틀을 조금 길게쓰면 다음과 같다.

struct CustomIterator: IteratorProtocol {
  typealias Element = Int
  func next() -> Int? {

  }
}

struct CustomSequence: Sequence {
  typealias Element = Int
  typealias Iterator = CustomIterator
  
  func makeIterator() -> CustomIterator {

  }
}

 

두개 다 Async 버전으로 하면 함수가 async로 바뀌고 명칭만 조금 바뀔뿐

struct AsyncCustomIterator: AsyncIteratorProtocol {
  typealias Element = Int
  func next() async -> Int? {

  }
}

struct AsyncCustomSequence: AsyncSequence {
  typealias Element = Int
  typealias AsyncIterator = AsyncCustomIterator

  func makeAsyncIterator() async -> AsyncCustomIterator {

  }
}

🫷AsyncStream

 

⭐️ 정의

 

AsyncStream은 위에서 말한 비동기 반복문에 사용될 AsyncSequence를 생산하는 구조체다.

 

🏭 생성 방법

 

생성 방법은 크게 2가지 방법이 있다.

그 중 continuation을 이용하는 방법이 있는데, 이 방법은 continuation을 생성했을 때

배운 목적과 아주 일치한다.

 

바로 이전 API와 호환성이 좋다.

 

🪜 Continuation 이용

 

대표적인 공통점은 똑같이 error 여부로 Throwing이 붙냐 안붙냐 차이가있다.

차이점은 continuation 생성할 때는 , resume 키워드를 사용했지만.

 

stream 생성 시에는 yiled와 finish를 사용한다.

let stream1 = AsyncStream<Int> { continuation in
  continuation.finish() // 종료
  continuation.yield(element 타입)
  continuation.yield(with: Result 타입)
}

struct CustomError: Error {
}

let stream2 = AsyncThrowingStream<Int, CustomError> { continuation in
  continuation.finish()
  continuation.finish(throwing: CustomError())
  continuation.yield(element타입)
}

 

🗂️ unfolding

 

간단한 비동기 반복 작업을 생성할 때 사용, 자주 사용되지는 않는다.

약간 테스트 할 때 사용할만한 ??

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

struct CustomError: Error {}

let stream2 = AsyncThrowingStream {
  throw CustomError()
}

 

📦 makeStream

 

마지막 방법은 바로 makeStream 메서드를 이용하는 방법이다.

 

이 방법의 특이한 점은 continuatino과 stream이 튜플 형태로 반환되기 때문에

클로저 방식처럼 안에 있는 것보다 더 많은 유연성을 제공한다.

 

버퍼 정책

  • unbounded: 제한 없음
  • bufferingOldest(number): 버퍼가 가득차면, 가장 오래된 number개까지 유지
  • bufferingNewest(number): 버퍼가 가득차면, 가장 최근 number개까지 유지
import Foundation

let (stream, continuation) = AsyncStream<Int>.makeStream(bufferingPolicy: .unbounded)


Task {
  for await st in stream {
    print(st)
  }

}


continuation.yield(1)
continuation.yield(2)
continuation.yield(3)
continuation.yield(4)

 

약간 Rx나 Combine 같은 느낌이다.

관찰은 stream으로 하고 값은 continuation yield를 통해보내고


출처

https://developer.apple.com/documentation/swift/sequence

 

Sequence | Apple Developer Documentation

A type that provides sequential, iterated access to its elements.

developer.apple.com

https://developer.apple.com/documentation/swift/iteratorprotocol

 

IteratorProtocol | Apple Developer Documentation

A type that supplies the values of a sequence one at a time.

developer.apple.com

https://developer.apple.com/documentation/swift/asyncsequence

 

AsyncSequence | Apple Developer Documentation

A type that provides asynchronous, sequential, iterated access to its elements.

developer.apple.com

https://developer.apple.com/documentation/swift/asynciteratorprotocol

 

AsyncIteratorProtocol | Apple Developer Documentation

A type that asynchronously supplies the values of a sequence one at a time.

developer.apple.com

https://developer.apple.com/documentation/swift/asyncstream

 

AsyncStream | Apple Developer Documentation

An asynchronous sequence generated from a closure that calls a continuation to produce new elements.

developer.apple.com

 

반응형