iOS/RxSwift

RxSwift 사용

HJ39 2023. 1. 14. 00:31

RxSwift

RxSwift는 데이터가 Stream 방식으로 흘러간다.

 

Observer

Observable안에 있는 내부 인스턴스들로 Observable의 값에 변화가 있을 때 Observer에게 알림이 가고, 등록한 Closure 실행

Subject

Observable과 Observer의 성격을 모두 가지고 있는 Protocol (이벤트 방출과, Subscribe를 이 타입 하나로 모두 가능)

subject 없이 이벤트 처리를 한다면 observer, Observable 두개 타입이 필요

Observable은 1:1로 이벤트를 방출하지만 1:multi로 이벤트를 여러 Observer에게 송신

Observable

RxSwift에서 제공하는 "나중에 생기는 데이터" 타입의 이름

Observer 인스턴스를 가지는 상태

value 인스턴스를 가지고 있다가, value가 변경되면 didSet을 통해 아이템 방출

Observable 주기

  1. Create
  2. Subscribe
  3. onNext (onNext 이후로 Observable 재사용 불가)
  4. onCompleted / onError
  5. Disposed

 

□ 예제 1

var disposeBag = DisposeBag()

    private func loadImage(from url: String) -> Observable<UIImage?> {
        return Observable.create { emitter in
            let task = URLSession.shared.dataTask(with: URL(string: url)!) { data, _, error in
                if let error = error {
                    emitter.onError(error)
                    return
                }
                guard let data = data,
                    let image = UIImage(data: data) else {
                    emitter.onNext(nil)
                    emitter.onCompleted()
                    return
                }

                emitter.onNext(image)
                emitter.onCompleted()
            }
            task.resume()
            return Disposables.create {
                task.cancel()
            }
        }
    }

Observable 타입으로 반환하는 함수이다.

Observable를 create 하고, emitter를 이용하여 데이터를 생성한다.

emiiter가 데이터를 성공적으로 가져오면 onNext()를 통해 전달하고 onCompleted() 된다.

Observable 사용이 모두 끝나면 Disposable을 해야 한다.

Disposable을 사용하지 않는 경우 ARC 메모리 관리를 할 때 Strong 참조를 하는데 Strong 참조를 한 상태에서 뷰의 참조가 끝나도 Reference Count가 남아있게 되어 순환참조가 발생하게 되고 메모리 누수가 발생한다. (Weak 참조를 하는 경우 Disposable을 하지 않아도 된다.)→ ARC 메모리 기법을 공부하면 자세하게 알 수 있다.

 

Events

next

어떤 항목을 배출하는데 사용

error

값을 내보내다가 오류가 발생한 경우 error이벤트 방출 후 스트림 종료

complete

성공적으로 next가 완료되었을 때 발생 후 스트림 종료

 

error, complete 가 발생한 경우에는 Dispose가 호출되고 스트림이 종료된다.

 

Operator

just

데이터가 1개인 경우 just를 통해 데이터를 내려보낸다.

from

데이터가 여러 개인 경우 from을 통해 데이터를 내려보낸다.

subscribe

위 예제에서 처럼 create뒤에 closure방식으로 바로 사용한다면. subscribe를 사용하지 않아도 된다.

Completed, Error로 Observable이 종료된 이후 Observable은 재사용할 수 없다.

dispose 등으로 끝난 이후 subscribe 함수를 다시 호출하여 사용할 수 있다.

Disposable

□ 예제 2

let disposable = Observable.from([1, 2, 3, 5, 6])
    .subscribe(onNext: { element in
        print(element)
        sleep(1)
    }, onCompleted: {
        print("completed")
    }, onDisposed: {
        print("disposed")
    })
    
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
    disposable.dispose()
}

// 1
// 2
// disposed


var disposeBag = DisposeBag()

button.rx.tap
    .subscribe(onNext: {
        print("Tap")
    }, onCompleted: {
        print("completed")
    }, onDisposed: {
        print("disposed")
    })
    .disposed(by: disposeBag)

첫 번째 코드와 두 번째 코드의 차이는 DisposeBag을 사용한 것과 UI에 적용한 점이 다르다.

첫 번째의 경우 stream을 종료하지만 두 번째의 경우에는 UI의 데이터를 계속해서 감시해야하기 때문에 종료하지 않고 DisposeBag에 담아 사용한다.


쓰레드 분기

observeOn

여러 번 호출할 수 있고 호출되면 그다음부터 동작하는 쓰레드를 변경할 수 있다.

 

subscribeOn

subscribeOn은 한번 호출했을 때 결정된 쓰레드를 고정하여 사용하고 이후 subscrbieOn을 다시 호출해도 쓰레드가 바뀌지 않는다.

ObserveOn()이 실행되지 전까지 쓰레드가 고정된다.

 

□ 예제 3

  1. 첫번째 줄(파란색 줄)에서 ObserveOn(주황색)을 실행시킨 경우 두 번째 줄부터 주황색 쓰레드가 사용된다.
  2. 두 번째 줄(동그라미 주황색 줄)에서 map()을 사용하여 모양만 바뀌었을 뿐 쓰레드는 변경되지 않고 주황색 쓰레드가 사용된다.
  3. 세 번째 줄(네모 주황색 줄)에서 subscribeOn(파란색)을 하는 경우 다음 데이터가 주황색 쓰레드를 사용하고 현재 사용하고 있는 쓰레드는 변경되지 않는다.
  4. 네 번째 줄(네모 주황색 줄)에서 ObserveOn(보라색)을 실행하는 경우 쓰레드가 보라색 쓰레드로 변경된다.

 

Stream 병합

Merge

여러개의 독립적인 Obeservable을 하나의 Observable에 합쳐서 보여준다.

Observable들의 데이터 타입이 같아야 한다.

(git branch Merge 하는 것과 같은 것 같다)

Zip

독립적인 Observable을 1:1 쌍으로 묶어서 합친다.

두 Observable 데이터 타입이 달라도 된다.

 

CombineLatest

두 Observable의 데이터 타입이 달라도 되고 1:1 매핑이 되지 않아도 된다.

조건에 맞게 합친다.

startWith

데이터들을 방출하기 전에 설정한 요소를 처음으로 시작하여 스트림을 시작할 수 있다.

(맨 앞에 덧붙이는 느낌)

concat

두개의 스트림을 단순하게 연결한 것

concatMap

각 스트림이 다음 스트림이 구독되기 전에 합쳐지는 것을 보장

더 많은 방법이 있는다. (3번 째 참고 사이트 링크에 참조)

 

Scheduler

MainScheduler

메인 쓰레드에서 가장 위에 존재

UI를 관리

SerialDispatchQueueScheduler

background에서 추출하는 일을 처리할 때 사용

ConcurrentDispatchQueueScheduler

SerialDispatchQueueScheduler와 같이 추출하는 일을 처리할 때 병렬적으로 사용

TestScheduler

테스트를 위한 스케줄러

 

 

 

# 참고한 사이트 

  1. https://rldd.tistory.com/131
  2. https://beomseok95.tistory.com/47
  3. https://thoonk.tistory.com/89
  4. https://dongminyoon.tistory.com/45
  5. https://ios-development.tistory.com/133
  6. https://ios-development.tistory.com/594

'iOS > RxSwift' 카테고리의 다른 글

Alamofire + RxSwift + MVVM  (0) 2023.03.05