timeout 은 지정한 시간 내에 값을 발행하지 않으면 선택적으로 지정한 에러를 발행하게 하는 Operator입니다.

굳이 “선택적”이라는 표현을 쓴 이유는, 에러를 지정하지 않으면 정상적으로 .finished 완료이벤트를 발행하기 때문입니다. (이렇게 사용할거라면 timeout을 사용할 이유가 없겠죠?)

기능

실행

enum MyError: Error {
  case timeoutError
}

let publisher = PassthroughSubject<String, MyError>()

let timeoutPublisher = publisher.timeout(.seconds(3), scheduler: DispatchQueue.main) {
  return .timeoutError // 타임아웃 시 발행할 에러
}

DispatchQueue.main.async {
  timeoutPublisher
    .sink { completion in
      switch completion {
      case .finished:
        print("finished")
      case .failure(let error):
        print("error: \\(error)")
      }
    } receiveValue: { value in
      print(value)
    }
    .store(in: &cancellables)
}

DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
  publisher.send("I'm not late! :)")
}

DispatchQueue.main.asyncAfter(deadline: .now() + 4) { // 지정시간보다 1초 늦음
  publisher.send("I'm too late! :(")
}

DispatchQueue.main.asyncAfter(deadline: .now() + 5) { // 지정시간보다 2초 늦음
  publisher.send("Another: I'm too late! :(")
}

// 결과
I'm not late! :)
I'm too late! :(
Another: I'm too late! :(
error: timeoutError

특이한 점은

I'm too late! :(

Another: I'm too late! :(

값이 구독됐다는 점이에요.

분명히 timeout 연산자는 3초로 지정했는데, 지정한 시간이후에 발행된 값들은 어떻게 구독될 수 있을까요?

그건 바로 timeout의 정확한 기능은 데이터 발행은 모두 구독시키지만 완료이벤트만 지정한 에러(이마저도 에러를 지정하지 않으면 .finished)로 발행하는 것이기 때문이에요!