본문 바로가기
Xcode/Swift - PlayGround

PlayGround) RxSwift-Error Handle

by 후르륵짭짭 2022. 2. 7.
728x90
반응형

안녕하세요! 후르륵짭짭 입니다.

머 한 것도 없는데, 벌써 한달이 지났습니다 ㅎㅎㅎ

요즘엔 React 개발에 나름 흥미를 가져가지고, 웹 개발도 작성 해볼까 생각 중입니다 ㅎㅎㅎ

사내에서 RxSwift를 사용할 때가 많은데, 

특히 Error 처리에 대해서 다뤄볼까 합니다.

찾으면 많이 나오지만,,,, 전 헷갈렸던거 위주로만 ㅋㅋㅋ

 

** RxError Create ** 

1. Create 방식

let _ = Observable<Int>.create { emiter in
            print("current cnt : \(self.cnt)")
            if self.cnt % 2 == 0 {
                emiter.onError(NSError(domain: "에러발생", code: 0))
            }

            emiter.onNext(self.cnt)
            self.cnt += 1

            return Disposables.create()
        }
        .subscribe(onNext:{ cnt in
            print("result : \(cnt)")
        })

2.  단순 함수형 방식

func errorHandler() -> Observable<Int> {
        if cnt % 2 == 0 {
            return .error(NSError(domain: "에러발생", code: 0))
        }
        return .just(cnt)
    }

3. 함수내에 Create 방식

func errorHandler3() -> Observable<Int>{
        return Observable<Int>.create { emiter in
            if self.cnt != 10 {
                print("Error 발생 - 1 cnt : \(self.cnt)")
                emiter.onError(NSError(domain: "에러발생", code: 0))
            }

            emiter.onNext(self.cnt)
            self.cnt += 1

            return Disposables.create()
        }

 

위와 같이 Create 방식을 참고하여 만들도록 하겠습니다.

 

** retry로 함수 호출 **

Error Handle 중에 retry가 있는데,

이 친구는 성공할 때 까지 무한 호출 입니다.

1.

let _ = Observable<Int>.create { emiter in
            if self.cnt != 10 {
                print("Error 발생 - 1 cnt : \(self.cnt)")
                emiter.onError(NSError(domain: "에러발생", code: 0))
            }

            emiter.onNext(self.cnt)
            self.cnt += 1

            return Disposables.create()
        }
        .retry()
        .subscribe(onNext:{ cnt in
            print("result : \(cnt)")
        })
        
//result 
Error 발생 - 1 cnt : 0
Error 발생 - 1 cnt : 1
Error 발생 - 1 cnt : 2
Error 발생 - 1 cnt : 3
Error 발생 - 1 cnt : 4
Error 발생 - 1 cnt : 5
Error 발생 - 1 cnt : 6
Error 발생 - 1 cnt : 7
Error 발생 - 1 cnt : 8
Error 발생 - 1 cnt : 9
result : 10

2. 번과 같은 방식은 한번만 호출 되고 끝납니다.

let _ = errorHandler2()
            .retry()
            .subscribe(onNext:{ cnt in
                print("result : \(cnt)")
            })
            
//결과
Error 발생 - 2 cnt : 1

3.

 let _ = errorHandler3()
            .retry()
            .subscribe(onNext:{ cnt in
                print("result : \(cnt)")
            })
            
//결과
Error 발생 - 1 cnt : 0
Error 발생 - 1 cnt : 1
Error 발생 - 1 cnt : 2
Error 발생 - 1 cnt : 3
Error 발생 - 1 cnt : 4
Error 발생 - 1 cnt : 5
Error 발생 - 1 cnt : 6
Error 발생 - 1 cnt : 7
Error 발생 - 1 cnt : 8
Error 발생 - 1 cnt : 9
result : 10

 

일를 통해서 Custom Error 를 다루기 위해서는 Create 방식이 필요합니다.

만약에 아래와 같이 겹치는 경우는 어떻게 될까요?

1. 선 Create  후 함수형 (Create 에러 발생)

let _ = errorHandler3()
.flatMap({_ in return self.errorHandler2()})
.retry()
.subscribe(onNext:{ cnt in
    print("result : \(cnt)")
})

//결과
Error 발생 - 3 cnt : 0
Error 발생 - 3 cnt : 1
Error 발생 - 3 cnt : 2
Error 발생 - 3 cnt : 3
Error 발생 - 3 cnt : 4
Error 발생 - 3 cnt : 5
Error 발생 - 3 cnt : 6
Error 발생 - 3 cnt : 7
Error 발생 - 3 cnt : 8
Error 발생 - 3 cnt : 9
result : 10

 

2. 후 Create 선 함수형 (함수 에러 발생)

let _ = errorHandler2()
.flatMap({_ in return self.errorHandler3()})
.retry()
.subscribe(onNext:{ cnt in
    print("result : \(cnt)")
})

//결과
Error 발생 - 2 cnt : 0

 

3. 선 Create  후 함수형 (함수 에러 발생)

func errorHandler3() -> Observable<Int>{
return Observable<Int>.create { emiter in
    emiter.onNext(self.cnt)
    self.cnt += 1

    return Disposables.create()
}
}
    
func errorHandler2() -> Observable<Int> {
if cnt != 10 {
    print("Error 발생 - 2 cnt : \(self.cnt)")
    return .error(NSError(domain: "에러발생", code: 0))
}
return .just(cnt)
}

let _ = errorHandler3()
.flatMap({_ in return self.errorHandler2()})
.retry()
.subscribe(onNext:{ cnt in
    print("result : \(cnt)")
})

//결과 
Error 발생 - 2 cnt : 0
Error 발생 - 2 cnt : 1
Error 발생 - 2 cnt : 2
Error 발생 - 2 cnt : 3
Error 발생 - 2 cnt : 4
Error 발생 - 2 cnt : 5
Error 발생 - 2 cnt : 6
Error 발생 - 2 cnt : 7
Error 발생 - 2 cnt : 8
Error 발생 - 2 cnt : 9
result : 10

 

4. 후 Create 선 함수형 (Create 에러 발생)

 func errorHandler2() -> Observable<Int> {
        return .just(cnt)
    }
    
func errorHandler3() -> Observable<Int>{
return Observable<Int>.create { emiter in
    if self.cnt != 10 {
        print("Error 발생 - 3 cnt : \(self.cnt)")
        emiter.onError(NSError(domain: "에러발생", code: 0))
    }

    emiter.onNext(self.cnt)
    self.cnt += 1

    return Disposables.create()
}
}

let _ = errorHandler2()
    .flatMap({_ in return self.errorHandler3()})
    .retry()
    .subscribe(onNext:{ cnt in
        print("result : \(cnt)")
    })

 

위의 실험 결과를 보면 단독으로 함수형만 있을 경우에는 

에러가 발생 했을 때, 한번만 호출되는 반면

Create가 있다면 어디서 에러가 발생했는지는 중요하지 않고

무조건 호출이 되는 것 같다!

 

** retry의 호출 위치 **

만약에 retry가 구역마다 있을 때는??

1.

{1 - 함수형 }retry {2 - Create형} retry 구역으로 나눠지게 된다.

따라서 {1}에서 문제가 없이 retry를 지나갔으면

{2}에서 문제가 발생하더라도 {1}로 넘어가지 않는다.

func errorHandler2() -> Observable<Int> {
print("errorHander2 호출 : \(cnt)")
return .just(cnt)
}

func errorHandler3() -> Observable<Int>{
return Observable<Int>.create { emiter in
    if self.cnt != 10 {
        print("Error 발생 - 3 cnt : \(self.cnt)")
        emiter.onError(NSError(domain: "에러발생", code: 0))
    }

    emiter.onNext(self.cnt)
    self.cnt += 1

    return Disposables.create()
}
}

let _ = errorHandler2()
.retry()
.flatMap({_ in return self.errorHandler3()})
.retry()
.subscribe(onNext:{ cnt in
    print("result : \(cnt)")
})

//결과 
errorHander2 호출 : 0
Error 발생 - 3 cnt : 0
Error 발생 - 3 cnt : 1
Error 발생 - 3 cnt : 2
Error 발생 - 3 cnt : 3
Error 발생 - 3 cnt : 4
Error 발생 - 3 cnt : 5
Error 발생 - 3 cnt : 6
Error 발생 - 3 cnt : 7
Error 발생 - 3 cnt : 8
Error 발생 - 3 cnt : 9
result : 10

 

2.

{1 - Create} retry {2 - Create} retry 구조일 경우에는 

2번에서 에러가 발생하더라도

아래와 같이 매번 {1 - Create}에서 Observable이 호출되니 주의해야한다.

func errorHandler3() -> Observable<Int>{
    return Observable<Int>.create { emiter in
        if self.cnt >= 5 && self.cnt < 10 {
            print("Error 발생 - 3 cnt : \(self.cnt)")
            emiter.onError(NSError(domain: "에러발생", code: 0))
        }

        emiter.onNext(self.cnt)

        return Disposables.create()
    }
}

let _ = Observable<Int>.create({emiter in
    self.cnt += 1
    print("Create 호출 : \(self.cnt)")
    if self.cnt <= 5 {
        print("Error 발생 - Create cnt :\(self.cnt)")
        emiter.onError(NSError(domain: "에러발생", code: 0))
    }
    emiter.onNext(self.cnt)
    return Disposables.create()
    })
    .retry()
    .flatMap({_ in return self.errorHandler3()})
    .retry()
    .subscribe(onNext:{ cnt in
        print("result : \(cnt)")
    })
    
//결과 
Create 호출 : 1
Error 발생 - Create cnt :1
Create 호출 : 2
Error 발생 - Create cnt :2
Create 호출 : 3
Error 발생 - Create cnt :3
Create 호출 : 4
Error 발생 - Create cnt :4
Create 호출 : 5
Error 발생 - Create cnt :5
Create 호출 : 6
Error 발생 - 3 cnt : 6
Create 호출 : 7
Error 발생 - 3 cnt : 7
Create 호출 : 8
Error 발생 - 3 cnt : 8
Create 호출 : 9
Error 발생 - 3 cnt : 9
Create 호출 : 10
result : 10

 

** Retry외 Error 처리 Rx 메소드 **

retry() 외에도

retry(max :)도 있고 

retryWhen()도 있다.

그런데 이러한 내용은 검색하면 많이 나와서

https://rhammer.tistory.com/351

 

RxSwift - retryWhen(_:)에 대해서 알아보자

Ch14. Error Handling in Practice p.292 - 294 RxSwift의 에러처리 방법에 대해서 알아보자. 크게 2가지가 있다. 1. Catch하여 처리하기 2. Retry하기 (Retry해도 실패하면 Catch하던가) 1은 Swift와 유사하..

rhammer.tistory.com

https://velog.io/@hansangjin96/RxSwift-Error-Handling-Operators

 

RxSwift) Error Handling Operators

Error Handling Operators

velog.io

이 두개의 블로그만 참고해도 큰 도움이 될 것 같다!

728x90
반응형

댓글