Swift

[Swift, Combine] AnyPublisher 를 async/await throws 로 사용해보자

insub4067 2023. 10. 4. 09:47

https://developer.apple.com/documentation/swift/withcheckedthrowingcontinuation(function:_:)

withCheckedThrowingContinuation(function:_:) | Apple Developer Documentation

Invokes the passed in closure with a checked continuation for the current task.

developer.apple.com


import Foundation
import Combine

extension AnyPublisher where Failure: Error {
    
    var asyncThrows: Output {
        get async throws {
            try await withCheckedThrowingContinuation { continuation in
                var cancellable: AnyCancellable?
                cancellable = first()
                    .sink { completion in
                        switch completion {
                        case .finished:
                            break
                        case .failure(let error):
                            continuation.resume(throwing: error)
                        }
                        cancellable?.cancel()
                    } receiveValue: { value in
                        continuation.resume(with: .success(value))
                    }
            }
        }
    }
}
import Foundation
import Combine

struct UserNetwork {
    
    private let network: Networkable
    private let baseUrl = "https://api.github.com/users/"
    private var url: (String) -> URL {{ query in URL(string: baseUrl + query)! }}
    
    init(network: Networkable = Network()) {
        self.network = network
    }
    
    func getUser(username: String) -> AnyPublisher<User, Error> {
        network.request(url: url(username))
    }
}
func didTapButton() {

        // AnyPublisher -> async throws
        Task {
            let user = try? await userNetwork.getUser(username: "insub4067").asyncThrows
            print(user)
        }

        // AnyPublisher
        userNetwork.getUser(username: "insub4067")
            .sink { completion in
                guard let error = completion.networkError else { return }
                switch error {
                case .badResponse:
                    print(error)
                case .statusCode(let status):
                    print(error, status)
                case .badUrl:
                    print(error)
                case .unknown:
                    break
                }
            } receiveValue: { user in
                print(user)
            }
            .store(in: &cancellable)
    }


https://github.com/insub4067/Combine-Testable-Network