RxSwift - 알아보기(Observable) [220221수정]

JSLee·2022년 2월 15일
0

RxSwift⚡️

RxSwift 란 ?

Reactive X + Swift 로써 여기서의 Reactive 는 데이터 스트림과 변화의 증식에 비동기 프로그래밍 이다
RxSwift 는 Swift 로 Reactive 적 프로그래밍을 위한 라이브러리 이다.


Why?🤷🏻‍♀️

그렇다면 왜 RxSwift 를 사용하여 비동기 프로그래밍을 해야하는가? 라는 의문점이 생기게 된다.
왜냐하면 이미 Swift 안에서 비동기 처리가 가능한 DispatchQueue 가 존재하고 PromisKit 라이브러리를 사용할수도 있다.
다양한 이유들이 존재한다. 일괄성있는 코드 , 확장이 불가능한 아키텍처 패턴 해결 , Thread 처리의 가벼움 등등
하지만 내가 느끼는 바로는 코드가 매우매우 깔끔해진다는 점 같다.ㅎㅎ


Observable

  • RxSwift 는 관찰자(Observer) 는 Observable을 구독(Subscribe) 한다. 라는 개념을 가지고 있다.
  • Observable 은 항상 관찰 가능한 상태를 유지하고 Event방출(Emit) 한다.
  • ObserverObservableEmit 하는 항목,항목 시퀀스에 반응 한다.

Observable Emit Event

Observable 은 3가지의 Event 를 방출(Emit) 한다.

onNext :

  • Observable은 Observable이 항목을 방출할 때마다 이 메서드를 호출합니다. 이 메소드는 Observable이 내보낸 항목을 매개변수로 사용합니다.

onError :

  • Observable은 예상 데이터 생성에 실패했거나 다른 오류가 발생했음을 나타내기 위해 이 메서드를 호출합니다.
  • 생명주기 가장 마지막에 방출한다.

onCompleted :

  • onNext 에서 Error가 방출되지 않은 경우 방출한다.
  • 생명주기 가장 마지막에 방출한다.

onError , onCompleted 가 방출된 이후에는 모든 리소스는 재정의 되어 Observable의 방출 행위는 더이상 이루어지지 않는다

Marble diagrams

Rx의 흐름은 marble diagrams 을 이용하여 쉽게 이야기 할수 있다.
천천히 살펴 보면...
가로로 길게 늘어서 화살표 는 생명주기 즉 라이프사이클 을 뜻한다. 그리고 그안에 있는
각각의 기호 들은 Observable 이 Emit(방출) 한 Event 이다. 또한 가장 우측에 위치한 vertical Bar 는 onCompleted 로써 Observable 방출에 종료를 의미한다.
또한 이렇게 모든 방출이 끝난 EventObserver 는 직사각형 박스(Operator)를 이용하여 처리,반응 하고 가장 맨아래에 화살표에 기호들처럼 EvetOperator 에 의해 변경되어 처리된다.
또한 앞써 설명했듯 X표시는 onError 를 뜻하고 라이프사이클에 마지막에 방출되어 그렇게 라이프사이클이 종료된다.

Observable 생성

Observable을 생성하기 위해서 Rx는 다양한 Operator를 제공합니다.
자주 사용되는 Operator 위주로 살펴보겠습니다.

Create

Create 는 직접적으로 Observer Method 를 호출 하여 Observable을 생성합니다.
또한 Observable 생성시 가장 기본적인 메소드이다.

    @objc func rxHandle() {
        Observable<String>.create { observer in
            observer.onNext("Next")
            observer.onCompleted()
            return Disposables.create()
        }.subscribe(
            onNext: { self.one.text = $0},
            onError: { print($0) },
            onCompleted: { self.two.text = "Completed" },
            onDisposed: { self.three.text = "Dispose" }
        ).disposed(by: disposeBag)
    }

Defer

Observer 가 Subscribe 할때 까지 Observable 을 생성하지 않고 Subscribe가 완료되면 각 Observer에 대해 새로운 Observable 을 생성합니다. Defer는 조건이 필요합니다.

       var value = false
        let observable = Observable<String>.deferred {
            value.toggle()
            if value {
                return Observable.from(["A"])
            }else{
                return Observable.from(["가"])
            }
        }
        observable.subscribe { event in
            switch event {
            case let .next(value):
                self.one.text = value
                self.two.text = value
                self.three.text = value
            default :
                print("라이프사이클 종료")
            }
        }.disposed(by: disposeBag)  

Just

특정 항목을 방출하는 Observable 생성
Just 는 하나의 항목만 방출합니다.
예를 들어 Just 의 인자가 1 이면 가능하지만 1,2,3 이면 작동이 불가 합니다.
그럴경우 Array로 묶은뒤 [1,2,3] 으로 인자를 보낼경우 작동이 가능합니다.
just 는 모든 항목을 한번에 방출합니다.

     let obs = Observable.just(1)
        obs.subscribe(onNext: {
            print($0)
        }).disposed(by: disposeBag)
       //print
       //1

     let obs = Observable.just([1,2,3])
        obs.subscribe(onNext: {
            print($0)
        }).disposed(by: disposeBag)
       //print
       //[1,2,3]

Of

두 개 이상의 요소를 방출하는 옵저버블을 생성합니다.
또한 of 의 경우 배열로 묶어 처리할때와 그렇지 않을 때 의 경우가 나뉩니다.
배열로 묶지 않는 경우엔 방출을 순서대로 진행합니다.
배열로 묶게 되면 한번에 모든 방출을 진행합니다

        Observable
            .of(1,2,3)
            .subscribe(onNext: {
                print($0)
            }).disposed(by: disposeBag)
        
        Observable
            .of([1,2,3])
            .subscribe(onNext: {
                print($0)
            }).disposed(by: disposeBag)
            //print
1
2
3


[1, 2, 3]

From

just와 마찬가지로 간단하게 observable을 생성할수 있습니다.
배열에 포함된 요소를 하나씩 순서대로 방출하는 옵저버블을 생성합니다.
of 의 경우와는 다르게 from 은 배열이 아닌이상 진행이 되지 않는다.
이유는 From 은 index를 추적하기 때문이고 그렇기에
of는 배열의 경우 배열 자체를 하나의 object 로 인식하여 방출시 배열의 요소가 모두 방출 되지만 index 를 추적하는 from의 경우 요소들을 순서대로 방출된다.

let number = [1,2,3,4,5] 

let source = Observable.from(number) 

source.subscribe { 
    print($0) 
}
//print
next(1) 
next(2) 
next(3) 
next(4) 
next(5) 
Completed

Range

특정 범위의 순차 정수를 방출하는 Observable 생성

증가되는 크기를 바꾸거나 감소하는 시퀀스를 생성하는 것은 불가능합니다. (그러기 위해서는 generate를 사용해야합니다)

Observable.range(start: 1, count: 10)
    .subscribe { print($0) }
    .disposed(by: disposeBag)

// print
next(1)
next(2)
..
next(10) 

Generate

initialState: 시작 값(가장 먼저 방출되는 값)

condition: 조건이 true일 경우에만 요소가 방출됨 (false일 경우 completed)

iterate: 값을 증가시키거나 감소시킬 경우 사용

let source = Observable.generate(
   initialState: 0,
   condition: { $0 < 3 },
   iterate: { $0 + 1 }
)

source.subscribe {
   print($0)
}
// print
next(0)
next(1)
next(2)
completed

Repeat

특정 항목을 여러 번 방출하는 Observable 생성

Observable.repeatElement("A")
    //.take(7) // 7개만 방출하고 종료 
    .subscribe { print($0) }
    .disposed(by: disposeBag) 

// print
"A"
...
무한루프 

take로 조건이 없으면 무한루프 된다.

Empty , Never , Throw

Empty

항목을 내보내지 않지만 정상적으로 종료되는 Observable을 만듭니다.
성공여부만 따지고 성공이면 생명주기 종료

Observable<Void>.empty()
    .subscribe { print($0) }
    .disposed(by: disposeBag)
    
// print 
completed 

Never


항목을 내보내지 않고 종료되지 않는 Observable을 만듭니다.

let observable = Observable<Any>.never() 
observable .subscribe { print($0) } 
.disposed(by: disposeBag) 
// 아무 것도 반환X

Throw


항목을 내보내지 않고 오류로 종료되는 Observable을 만듭니다.

Doucuments 상 에서는 Throw 로 명시 되지만 프로그래밍 에서는 error 로 사용한다.

enum MyError: Error {
    case error
}

Observable<Void>.error(MyError.error)
    .subscribe { print($0) }
    .disposed(by: disposeBag)
    
// print 
error(error)

Interval

지정한 시간 간격을 두고 주기 마다 Emit 되는 Observable 을 생성한다. Interval Operator 의 경우 Completed 되지 않고 무한한 시퀀스를 생성한다.
dispose 되지 않는 다면 Subscribe 이후에 계속 반복된다.

  • period : 지정하는 주기를 의미한다. 5초 설정시 5초 마다 Observable 을 반환 한다.

  • scheduler : Task 를 진행할 Thread 를 지정한다.

// interval
let observable = Observable<Int>
                      .interval(.seconds(1), scheduler: MainScheduler.instance)
                      .subscribe { print($0) }
                      
// 직접 해제시켜야함
DispatchQueue.main.asyncAfter(deadline: .now() + 6) {
    observable.dispose()                     
}

// next(1)
// next(2)
// next(3)
// next(4)
// next(5)

Timer

Subscribe 이후에 딜레이를 가지고 Observable이 반환된다. 또한 유한한 시퀀스 이다.

  • dueTime : 첫 값이 생성되기 까지의 시간

  • period : 다음 값이 생성되는 주기

  • scheduler : Task 가 진행될 Thread 지정

dueTime 이 10초이면 subscribe 된후 10초 뒤에 첫번째 값을 받을수 있다.
period 의 default 는 nil 이고 지정하지 않으면 Observable 을 더이상 생성하지 않는다.

// 
timer Observable<Int> 
.timer(.seconds(1), scheduler: MainScheduler.instance) 
.subscribe { print($0) } 
.disposed(by: disposeBag) 
// next(0) 
// completed 
// timer with period 
Observable<Int>.timer(.seconds(1),period:.seconds(1), scheduler: MainScheduler.instance) 
.subscribe { print($0) } 
.disposed(by: disposeBag) 

// next(0) 
// next(1) 
// next(2) 
// next(3) 
// next(4) 
// :
  • interval 은 Seconds

  • timer 는 dueTime

  • interval completed X

  • timer completed O

profile
iOS/Android/FE/BE

0개의 댓글