RxSwift 시작하기(Observable) - 2

DevelopRecord·2022년 7월 16일
0

RxSwift

목록 보기
2/7

이제부터 Operator들을 하나씩 써볼 계획입니다.
바로 시작할게요.

우선 ReactiveX는 반응을 보이는, 관찰가능한 이라는 키워드가 있었죠.

어떠한 대상을 관찰한다면 RxSwift를 사용하지 않는다면,

willSetdidSet을 사용했었습니다.

하지만 RxSwift에서는 Observable을 사용합니다

앞으로 RxSwift를 사용한다면 가장 많이 보게될 녀석일 것입니다.

관찰가능한

ReactiveX에서 옵저버는 Observable을 구독한다. Obseravable이 배출하는 하나 또는 연속된 항목에 옵저버는 반응한다.

Observable은 값이 들어왔을 때 세가지의 액션이 존재합니다.

next, error, complete

next
Observable은 새로운 어떠한 값(파라미터)에 대한 항목들을 방출(emit)할 때마다 이 메서드를 호출합니다.

error
error는 말 그대로, 특정 에러 조건을 만족했을 때 이 메서드를 호출합니다.
그리고 해당 Observable은 스트림을 종료한다고 해요.

complete
Observable에서 next 메서드가 모든 항목을 방출하고 나서 할일이 끝났을 때 complete 메서드가 호출됩니다.

중요
하지만 만약에.. 아직 next 메서드가 항목들을 전부 방출하지 않았는데 도중에 error 메서드가 호출된다면?
다시말해서 complete가 나지 않은 상태에서 error가 나버리면 그 순간 멈춥니다. complete 메서드를 호출하지 않고요.

결론은 complete가 호출되려면 next 메서드로 모든 항목들이 방출되어야 하고, error 메서드가 호출되지 않아야 합니다.

예제를 통해 살펴보면 이해가 빠를 거예요.
일단 설치하고 봐야겠죠?
저는 Swift Package Manager로 설치했습니다. 버전은 6.0.0 입니다.
https://github.com/ReactiveX/RxSwift

전체 코드

import UIKit
import RxSwift

class ViewController: UIViewController {

    // MARK: - Properties

    private var disposeBag: DisposeBag = DisposeBag()

    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()
        configureUI()
    }

    // MARK: - Helpers

    func configureUI() {
        checkArrayEven(arr: [1, 3, 5, 6, 9])
            .subscribe { event in
            switch event {
            case .next(let value):
                print("next: \(value)")
            case .error(let error):
                print("error: \(error)")
            case .completed:
                print("completed!!")
            }
        }.disposed(by: disposeBag)
    }

    func checkArrayEven(arr: [Int]) -> Observable<Int> {
        return Observable.create { observer in
            for i in arr {
                if i % 2 == 0 {
                    observer.onError(NSError(domain: "ERROR: 짝수가 감지되었습니다.", code: 0, userInfo: nil))
                    break
                }

                observer.onNext(i)

                sleep(1)
            }
            observer.onCompleted()

            return Disposables.create()
        }
    }
}

Observable 객체를 리턴하는 함수부터 살펴볼게요.

func checkArrayEven(arr: [Int]) -> Observable<Int> {
        return Observable.create { observer in
            for i in arr {
                if i % 2 == 0 {
                    observer.onError(NSError(domain: "ERROR: 짝수가 감지되었습니다.", code: 0, userInfo: nil))
                break
            }

            observer.onNext(i)

            sleep(1)
        }
        observer.onCompleted()

        return Disposables.create()
    }
}

일단 저는 처음엔 헷갈리지 않게 아래 순서로 함수를 만들었습니다.

  1. Disposable 객체를 리턴합니다. (나중에 다시 설명)
  2. Observable 객체를 리턴하고 create라는 메서드를 사용합니다.
  3. error를 발생시킬 수 있는 조건문을 작성하고 error 메서드를 사용합니다.
  4. error 조건을 만족하지 않는다면 next 메서드를 사용해서 값을 방출합니다.
  5. 다 방출했다면(error가 호출되지 않는다면) complete 메서드를 호출합니다.

하나씩 살펴볼게요.
Disposable 객체는 사전적 용어로

사용 후 버리는, 일회용의

라는 의미를 가지고 있어요. 즉 complete 메서드가 호출되고 끝나면 사용할 필요가 없어지니 버리겠다 라는 의미정도로 생각하시면 될 것 같습니다.
나중에 다시 설명할게요.

Observable 객체는 create라는 메서드를 제공하는데 여기에 observer를 파라미터로 받고 이 observer가 Disposable 객체를 반환하는 클로저를 갖고 있어요.

error를 발생시킬 조건. 즉, 저는 짝수값을 찾았을 때 에러를 방출시킬 겁니다.

error를 발생시키지 않는다면 next 메서드로 값을 sleep함수를 이용해서 1초 단위로 프린트 합니다.
sleep은 그냥 천천히 보기 편하려고 넣었습니다.

모두 프린트 했다면 complete 메서드를 호출하고 완료합니다.

이제 이 값을 보려면 바로 호출하면 나오지 않아요.
우리는 구독이라는 것을 할 겁니다.

Subscribe

Observable은 subscribe라는 메서드를 제공합니다.

checkArrayEven(arr: [1, 3, 5, 6, 9])
    .subscribe { event in
    switch event {
    case .next(let value):
        print("next: \(value)")
    case .error(let error):
        print("error: \(error)")
    case .completed:
        print("completed!!")
    }
}.disposed(by: disposeBag)

이렇게 next에서 값을 하나씩 뽑아오다가 에러 조건을 만족시킨다면 error 메서드가 호출되고 checkArrayEven 함수에서 observer에 등록된 에러메시지를 출력할 거예요.


들어온 값이 next 메서드를 통해 1초 단위로 들어오다 6을 만나서 error 메서드가 호출되고(에러메시지를 출력) complete 메서드는 호출되지 않은 채 종료가 됩니다.
마지막에 .disposed(by: disposeBag)은 아까 말씀드렸던 폐기한다는 내용입니다.
disposeBag은 제가 전역변수로 하나 만들었습니다. 이것도 나중에 설명을 다시 할게요.

private var disposeBag: DisposeBag = DisposeBag()

만약 에러 조건을 만족시키지 않는다면 아래처럼 complete까지 호출되고 정상적으로 종료됩니다.

이렇게 Observable이 어떤 역할인지 어떤 메서드를 가지고 있는지 알아보고 간단하게 사용해봤는데요.

사실 위 예제는 개발을 하면서 딱히 쓸데없는 주제라고 합니다.

그래도 어떤식으로 동작하는지 원리는 이해했으니까 그거면 됐다고 생각해요..

다음은 subscribe, dispose에 대해 알아보겠습니다.

틀린 내용이 있으면 지적해 주세요..!

참고

마기님

0개의 댓글