개발/Swift

Observable → Async / Await 으로 변환하여 API 처리하기 (AsyncThrowingStream, withCheckedThrowingContinuation)

덤벨로퍼 2025. 4. 16. 16:35

기존 삭제 기능 은 Observable을 사용하여 구현되었다

    private func deleteImage(accessKey: String) -> Observable<Response> {
        return networking.request(.deleteImage(accessKey: accessKey)).asObservable()
    }
    

문제점은 해당 API를 요청하는데 사용 하는곳은 async/await 구조로 되어 있다는것이다.

그렇다고 Base 네트워크까지 건드릴수는 없기 떄문에 네트워킹 구현체 부분은 수정할수없다

그럼 응답을 처리하는곳에서 Rx→ async/await 으로 바꿔주는 로직이 필요하다.

EX> Usecase

withCheckedThrowingContinuation

웹소켓이나 지속적인 응답을 받는게 아니라

API 호출처럼 1회성 호출이라면 이게 더 적합하다

    func deleteImage(accessKey: String) async throws -> Response {
        return try await withCheckedThrowingContinuation { continuation in
            let disposable = deleteImage(accessKey: accessKey)
                .subscribe(
                    onSuccess: { response in
                        continuation.resume(returning: response)
                    }, onFailure: { error in
                        continuation.resume(throwing: error)
                    }
                )
        }
    }
    
    
    // 사용 
     _ = try await Service().deleteImage(accessKey: key)

AsyncStream → AsyncThrowingStream

  • 웹소켓이나 지속적인 응답을 필요로 할떄 적합한 방법
  • AsyncStream 을 사용하면 에러를 던져줄수는 없다

await 에서 에러를 받아서 사용할경우에는 이것을 쓰면 안되고

AsyncThrowingStream 을 사용해야 한다

 func deleteImage(accessKey: String) -> AsyncThrowingStream<Response, Error> {
        AsyncThrowingStream { continuation in
            let disposable = deleteImage(accessKey: accessKey)
                .subscribe(
                    onSuccess: { response in
                        continuation.yield(response)
                    },
                    onFailure: { error in
                        continuation.finish(throwing: error)
                    }
                )
            continuation.onTermination = { _ in
                disposable.dispose()
            }
        }
    }

만약 에러 처리가 필요 없다면

func deleteImage(accessKey: String) -> AsyncStream<Response> {
        AsyncStream { continuation in
            let disposable = deleteImage(accessKey: accessKey)
                .subscribe(
                    onSuccess: { response in
                        continuation.yield(response)
                    }
                )
            continuation.onTermination = { _ in
                disposable.dispose()
            }
        }
    }

사용하는곳은 for await 을 써줘야 한다

for try await _ in Service().deleteImage(accessKey: key) { }