Post

Rx ↔ Combine

Rx ↔ Combine 변환 feat. RxCombine

RxCombine 라이브러리 사용

https://github.com/CombineCommunity/RxCombine

1
.package(url: "https://github.com/CombineCommunity/RxCombine.git", from: "1.6.0")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
TodosAPI.fetchTodosWithPublisher(page: 1)
            .asObservable()
            .subscribe (onNext: {
                print("onNext \($0)")
            }, onError: {
                print("onError \($0)")
            }, onCompleted: {
                print("onCompleted")
            }, onDisposed: {
                print("onDisposed")
            }).disposed(by: disposeBag)
        
        
        
        TodosAPI.fetchTodosWithObservable(page: 1)
            .publisher
            .sink { completion in
                switch completion {
                case .finished:
                    print("finished")
                case .failure(let failure):
                    print("failure: \(failure)")
                }
            } receiveValue: { response in
                print("response:\(response)")
            }.store(in: &subscriptions)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
static func fetchTodosWithPublisher(page: Int = 1) -> AnyPublisher<BaseListResponse<Todo>, ApiError> {
        
        let urlString = baseURL + "/todos" + "?page=\(page)"
        guard let url = URL(string: urlString) else {
            return Fail(error: ApiError.notAllowedUrl).eraseToAnyPublisher()
        }
        
        var urlRequest = URLRequest(url: url)
        urlRequest.httpMethod = "GET"
        urlRequest.addValue("application/json", forHTTPHeaderField: "accept")
        
         return URLSession.shared.dataTaskPublisher(for: urlRequest)
            .tryMap({ (data: Data, response: URLResponse) -> Data in
                print("data: \(data)")
                print("response: \(response)")
                
             
                 guard let httpResponse = response as? HTTPURLResponse else {
                    print("bad status code")
                    
                    throw ApiError.unknown(nil)
                }
                
                switch httpResponse.statusCode {
                case 401:
                    throw ApiError.unauthorized
                default: print("default")
                }
                
                if !(200...299).contains(httpResponse.statusCode) {
                    throw ApiError.badStatus(code: httpResponse.statusCode)
                }
                
               return data
            })
            
            .decode(type: BaseListResponse<Todo>.self, decoder: JSONDecoder()) //JSON -> Struct 로 변경 즉 디코딩 즉 데이터 파싱
            .tryMap({ response in // 상태 코드는 200인데 파싱한 데이터에 따라서 에러처리
                guard let todos = response.data,
                        !todos.isEmpty
                else {
                    throw ApiError.noContent
                }
                
                return response
            })
            .mapError({ err -> ApiError in
                if let error = err as? ApiError { // ApiError 에러라면
                    return error
                }
                
                if let _ = err as? DecodingError { // 디코딩 에 러라면
                    return ApiError.decodingError
                }
                
                return ApiError.unknown(nil)
            })
            .eraseToAnyPublisher()
        
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
static func fetchTodosWithObservable(page: Int = 1) -> Observable<BaseListResponse<Todo>> {
        
        let urlString = baseURL + "/todos" + "?page=\(page)"
        guard let url = URL(string: urlString) else {
            return Observable.error(ApiError.notAllowedUrl)
        }
        
        var urlRequest = URLRequest(url: url)
        urlRequest.httpMethod = "GET"
        urlRequest.addValue("application/json", forHTTPHeaderField: "accept")
         
        return URLSession.shared.rx.response(request: urlRequest)
            .map({
                (response: HTTPURLResponse, data: Data) -> BaseListResponse<
                    Todo
                > in
                print("data: \(data)")
                print("response: \(response)")
                
                guard let httpResponse = response as? HTTPURLResponse else {
                    print("bad status code")
                    
                    throw ApiError.unknown(nil)
                }
                
                switch httpResponse.statusCode {
                case 401:
                    throw ApiError.unauthorized
                default: print("default")
                }
                
                if !(200...299).contains(httpResponse.statusCode) {
                    throw ApiError.badStatus(code: httpResponse.statusCode)
                }
                
                do {
                    //JSON -> Struct 로 변경 즉 디코딩 즉 데이터 파싱
                    let listResponse = try JSONDecoder().decode(
                        BaseListResponse<Todo>.self, from: data)
                    
                    // 상태 코드는 200인데 파싱한 데이터에 따라서 에러처리
                    guard let todos = listResponse.data,
                          !todos.isEmpty
                    else {
                        throw ApiError.noContent
                    }
                    return listResponse
                    
                } catch {
                    // decoding error
                    throw ApiError.decodingError
                }
            })
    }
This post is licensed under CC BY 4.0 by the author.

Trending Tags