[swift] RxSwift에서의 오류 유형 및 해결 방법

RxSwift는 강력한 리액티브 프로그래밍 라이브러리로, iOS 앱 개발에서 비동기 작업을 처리할 때 많이 사용됩니다. 하지만 RxSwift를 사용하다 보면 종종 다양한 종류의 오류에 부딪힐 수 있습니다. 이번 포스트에서는 주요한 RxSwift 오류 유형과 그에 대한 해결 방법에 대해 알아보겠습니다.

1. Observable에서 ElementNotReady 오류 발생

ElementNotReady 오류는 Observable에서 이벤트가 아직 발생하지 않았음을 나타냅니다. 이 오류는 주로 flatMap, filter, take 등의 연산자를 사용할 때 발생하는 경우가 많습니다. 이 문제를 해결하기 위해서는 flatMap 연산자의 resultSelector 클로저를 함께 사용하여 오류를 방지할 수 있습니다.

let observable = Observable<String>.just("Hello")
observable
    .flatMap { value in
        return Observable<String>.just(value + " RxSwift")
    }
    .subscribe(onNext: { value in
        print(value)
    })
    .disposed(by: disposeBag)

2. 메모리 누수(Memory Leak)

RxSwift에서는 Observable의 구독을 취소하지 않으면 메모리 누수가 발생할 수 있습니다. 이를 해결하기 위해 disposeBag을 사용하여 옵저버블을 구독한 후에는 적절한 시점에 구독을 취소해야 합니다. 보통 UIViewControllerviewWillDisappear 또는 deinit 메소드에서 disposeBag을 비워주는 것이 권장됩니다.

class MyViewController: UIViewController {

    private let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
            .subscribe(onNext: { value in
                print(value)
            })
            .disposed(by: disposeBag)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        disposeBag = DisposeBag()
    }

}

3. UI 업데이트가 안되는 문제

RxSwift를 사용하면 비동기 작업을 쉽게 처리할 수 있지만, UI 업데이트는 메인 스레드에서 진행되어야 합니다. 만약 Observable의 이벤트가 메인 스레드가 아닌 다른 스레드에서 발생하는 경우, UI 업데이트가 제대로 이루어지지 않을 수 있습니다. 이 문제를 해결하기 위해서는 observeOn 연산자를 사용하여 메인 스레드로 이벤트를 보내야 합니다.

Observable.just(5)
    .observeOn(MainScheduler.instance)
    .subscribe(onNext: { value in
        label.text = "\(value)"
    })
    .disposed(by: disposeBag)

4. 네트워크 요청에서의 오류 처리

네트워크 요청은 주로 Observable을 사용하여 처리되는 경우가 많습니다. 그러나 네트워크 요청에서 오류가 발생할 때는 어떻게 처리해야 할까요? RxSwift에서는 네트워크 요청을 flatMap 연산자와 함께 사용하여 오류를 처리할 수 있습니다.

func fetchData() -> Observable<[String]> {
    return Observable.create { observer in
        // 네트워크 요청 수행
        // ...

        if success {
            observer.onNext(response)
            observer.onCompleted()
        } else {
            observer.onError(NetworkError.invalidResponse)
        }

        return Disposables.create {}
    }
}

fetchData()
    .flatMap { response in
        return Observable<[String]>.just(response)
    }
    .subscribe(onNext: { value in
        print(value)
    }, onError: { error in
        print(error)
    })
    .disposed(by: disposeBag)

참고 자료