[iOS 10주차] RxSwift 1부: Observable, Trait

DoyleHWorks·2024년 12월 24일
1

Observer & Observable

ReactiveX의 Swift 라이브러리인 RxSwift의 핵심 구성 요소는 Observable과 이를 구독하여 이벤트를 처리하는 Observer이다.

Observer Pattern
https://refactoring.guru/design-patterns/observer

Observable

Observable은 데이터를 방출하는 스트림이다. (시간 개념)

Observable은 데이터를 비동기적으로 생성하고 방출한다. 데이터는 이벤트로 표현되며, onNext, onError, onCompleted 세 가지 유형이 있다.

  • onNext: 새 데이터를 방출
  • onError: 오류 발생 시 호출
  • onCompleted: 데이터 스트림 종료를 알림

Observable 생성

Observable.create

Observable.create는 개발자가 커스텀하게 이벤트를 정의할 수 있도록 제공한다.

import RxSwift

let customObservable = Observable<String>.create { observer in
    observer.onNext("Hello")
    observer.onNext("RxSwift")
    observer.onCompleted() // 스트림 종료
    return Disposables.create()
}

customObservable.subscribe(
    onNext: { print("onNext:", $0) },
    onError: { print("onError:", $0) },
    onCompleted: { print("onCompleted") },
    onDisposed: { print("onDisposed") }
)

Observable.just

하나의 값을 방출하는 Observable을 생성한다.

let observable = Observable.just("Single Value")
observable.subscribe(onNext: { print($0) })

Observable.of

여러 값을 순차적으로 방출하는 Observable을 생성한다.

let observable = Observable.of(1, 2, 3, 4, 5)
observable.subscribe(onNext: { print($0) })

Observable.from

배열과 같은 Sequence로부터 순차적으로 방출하는 Observable을 생성한다.

let numbers = [1, 2, 3, 4, 5]
let observable = Observable.from(numbers)
observable.subscribe(onNext: { print($0) })

Observable.interval

지정한 시간 간격으로 값을 방출한다. 주로 타이머나 반복 작업에 사용된다.

let observable = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
observable.subscribe(onNext: { print($0) }).disposed(by: DisposeBag())

구독 및 처리

subscribe

subscribe는 Observable을 구독하여 이벤트를 처리하는 메서드이다. 주로 onNext, onError, onCompleted 핸들러를 정의한다.

let observable = Observable.of(1, 2, 3)
observable.subscribe(
    onNext: { print("onNext:", $0) },
    onError: { print("onError:", $0) },
    onCompleted: { print("onCompleted") }
)

Cold Observable & Hot Observable

  • Cold Observable: 구독자가 있을 때만 데이터를 방출(비유: Netflix).
    let coldObservable = Observable.from([1, 2, 3])
    coldObservable.subscribe { print($0) }
  • Hot Observable: 구독자 여부와 관계없이 데이터를 방출(비유: TV).
    let subject = PublishSubject<String>()
    subject.onNext("Hot") // 구독 전에 방출된 데이터는 받을 수 없음
    subject.subscribe { print($0) }
    subject.onNext("Observable")

DisposeBag

RxSwift의 메모리 관리를 위해 사용하며, 구독을 명시적으로 해제하지 않아도 DisposeBag이 해당 구독을 자동으로 해제한다.
기본적으로 구독 후에는 disposed(by: disposeBag) 을 호출해서 구독 해제를 명시해야 한다.
subscribe 를 수행하면 Disposable 객체가 되고, 이를 DisposeBag 안에 담으면 DisposeBag 이 메모리에서 해제될 때 구독의 해제가 함께 일어난다.

let disposeBag = DisposeBag()

Observable.of("Rx", "Swift")
    .subscribe { print($0) }
    .disposed(by: disposeBag)

.disposed(by:)를 호출하지 않았는데도 onDisposed가 출력되는 이유는 subscribe로 생성된 Disposable 객체가 구독이 끝나거나 오류가 발생했을 때 자동으로 해제(dispose)되기 때문입니다.

Observable의 생명주기

  • ObservableonNext, onError, 또는 onCompleted 이벤트 중 하나가 발생하면 구독이 종료된다.
  • 구독이 종료되면 해당 Disposable도 자동으로 해제된다. 따라서 명시적으로 .disposed(by:)를 사용하지 않아도 onDisposed는 호출된다.

onDisposed의 호출 시점:

  • onDisposedObservable의 구독이 종료될 때 호출된다.
  • 종료 조건은 다음 중 하나이다:
    • onError 이벤트가 발생할 때
    • onCompleted 이벤트가 발생할 때
    • 수동으로 dispose()를 호출할 때

요약:

.disposed(by:)를 사용하지 않아도 Observable의 생명주기가 끝나면 자동으로 onDisposed가 호출된다. 하지만, 명시적으로 메모리 관리를 하고 싶거나, 구독이 무한히 지속될 수 있는 상황에서는 .disposed(by:)를 사용하는 것이 필수적이다.


Trait

Trait는 Observable의 특수한 형태로, 단일 이벤트나 특정 이벤트 흐름을 명확히 표현하기 위해 사용된다.

Single

단 하나의 값 또는 에러를 방출한다.
하나의 값을 방출하거나, 에러를 방출하면 곧바로 스트림이 종료된다.
( onSuccess, onFailure )

let single = Single<String>.create { single in
    single(.success("Single Success"))
    return Disposables.create()
}

single.subscribe { event in
    switch event {
    case .success(let value):
        print("Success:", value)
    case .failure(let error):
        print("Error:", error)
    }
}

Maybe

값을 방출하거나, 방출하지 않고 완료하거나, 에러를 방출할 수 있다.
( onSuccess, onError, onCompleted )

let maybe = Maybe<String>.create { maybe in
    maybe(.success("Maybe Value"))
    maybe(.completed) // 값을 방출하지 않을 수도 있음
    return Disposables.create()
}

maybe.subscribe { event in
    switch event {
    case .success(let value):
        print("Success:", value)
    case .completed:
        print("Completed")
    case .failure(let error):
        print("Error:", error)
    }
}

Completable

값을 방출하지 않고 완료하거나 에러를 방출한다.
( onCompleted, onError )

let completable = Completable.create { completable in
    completable(.completed)
    return Disposables.create()
}

completable.subscribe {
    print("Completed")
} onError: { error in
    print("Error:", error)
}
profile
Reciprocity lies in knowing enough

0개의 댓글