RxSwift - Observable, Subject

준우·2024년 7월 24일
0

Swift 이야기

목록 보기
19/19
post-thumbnail

Observable

시간에 따라 변하는 데이터의 스트림

Observable

시간에 따라 발생하는 일련의 이벤트를 전달하는 스트림
3가지 종류의 이벤트를 방출함

  • next : 새로운 데이터를 방출
  • error : 에러가 발생하여 스트림이 종료
  • completed : 더 이상 데이터가 없음을 나타내고 스트림이 종료
import RxSwift

// Observable 생성
let observable = Observable<Int>.create { observer in
    observer.onNext(1)
    observer.onNext(2)
    observer.onNext(3)
    observer.onCompleted()
    return Disposables.create()
}

// Observable 구독
let disposeBag = DisposeBag()
observable.subscribe(
    onNext: { value in
        print("Next:", value)
    },
    onError: { error in
        print("Error:", error)
    },
    onCompleted: {
        print("Completed")
    }
).disposed(by: disposeBag)

Single

하나의 next 이벤트 또는 하나의 error 이벤트만 방출하는 스트림
네트워크 요청에서 많이 사용됨

  • 성공 : 하나의 값(.success) 을 방출한 후 종료
  • 실패 : 하나의 에러(.error) 를 방출하고 종료
import RxSwift

let disposeBag = DisposeBag()

// Single 예제
let single = Single<String>.create { single in
    let success = true
    if success {
        single(.success("Hello, RxSwift!"))
    } else {
        single(.error(NSError(domain: "Error", code: -1, userInfo: nil)))
    }
    return Disposables.create()
}

single.subscribe(
    onSuccess: { value in
        print("Success:", value)
    },
    onError: { error in
        print("Error:", error)
    }
).disposed(by: disposeBag)

Completable

next 이벤트를 방출하지 않고 오직 완료(completed) 또는 에러(error) 이벤트만 방출

결과가 필요 없는 작업(파일 삭제, 데이터베이스 처리) 에서 사용됨

  • 성공: 완료 이벤트(.completed)만 방출.
  • 실패: 에러 이벤트(.error)만 방출.
let completable = Completable.create { completable in
    let success = true
    if success {
        completable(.completed)
    } else {
        completable(.error(NSError(domain: "Error", code: -1, userInfo: nil)))
    }
    return Disposables.create()
}

completable.subscribe(
    onCompleted: {
        print("Completed")
    },
    onError: { error in
        print("Error:", error)
    }
).disposed(by: disposeBag)

Maybe

Single과 Completable을 결합한 형태
하나의 값(.success), 완료(.completed), 또는 에러(.error) 이벤트를 방출할 수 있습니다.
결과가 있을 수도 있고 없을 수도 있는 비동기 작업에서 사용됨.

  • 성공: 하나의 값(.success)을 방출하거나 완료(.completed) 이벤트를 방출.
  • 실패: 하나의 에러(.error) 이벤트를 방출.
let maybe = Maybe<String>.create { maybe in
    let success = true
    if success {
        maybe(.success("Hello, Maybe!"))
    } else {
        maybe(.completed)
    }
    return Disposables.create()
}

maybe.subscribe(
    onSuccess: { value in
        print("Success:", value)
    },
    onCompleted: {
        print("Completed")
    },
    onError: { error in
        print("Error:", error)
    }
).disposed(by: disposeBag)

Subject

Observable과 Observer를 동시에 구현하는 특별한 종류의 스트림입니다. 
Subject는 이벤트를 방출할 수 있고, 동시에 다른 Observable을 구독하여 이벤트를 받을 수도 있습니다.

  • PublishSubject
  • BehaviorSubject
  • ReplaySubject
  • AsyncSubject

PublishSubject

새로운 구독자가 구독을 시작한 시점 이후에 발생한 이벤트만 전달합니다.
구독을 시작하기 전에 발생한 이벤트는 전달되지 않음

import RxSwift

let disposeBag = DisposeBag()

// PublishSubject 생성
let publishSubject = PublishSubject<String>()

// 구독
publishSubject.subscribe(onNext: {
    print("Subscriber 1 received: \($0)")
}).disposed(by: disposeBag)

publishSubject.onNext("Hello")
publishSubject.onNext("World")

// 새로운 구독자 추가
publishSubject.subscribe(onNext: {
    print("Subscriber 2 received: \($0)")
}).disposed(by: disposeBag)

publishSubject.onNext("RxSwift")

/// 출력 결과
Subscriber 1 received: Hello
Subscriber 1 received: World
Subscriber 1 received: RxSwift
Subscriber 2 received: RxSwift

BehaviorSubject

초기 값을 가지며, 구독자가 구독을 시작할 때 가장 최근에 발생한 이벤트를 전달합니다.
구독자가 없을 때도 값을 유지함.

// BehaviorSubject 생성
let behaviorSubject = BehaviorSubject<String>(value: "Initial Value")

// 구독
behaviorSubject.subscribe(onNext: {
    print("Subscriber 1 received: \($0)")
}).disposed(by: disposeBag)

behaviorSubject.onNext("Hello")

// 새로운 구독자 추가
behaviorSubject.subscribe(onNext: {
    print("Subscriber 2 received: \($0)")
}).disposed(by: disposeBag)

behaviorSubject.onNext("World")

/// 출력 결과
Subscriber 1 received: Initial Value
Subscriber 1 received: Hello
Subscriber 2 received: Hello
Subscriber 1 received: World
Subscriber 2 received: World

ReplaySubject

버퍼 크기를 가지며, 새로운 구독자에게 버퍼에 저장된 모든 이벤트를 재생합니다.
버퍼 크기에 따라 최신 n개의 이벤트를 저장하고 전달함

// ReplaySubject 생성 (버퍼 크기 2)
let replaySubject = ReplaySubject<String>.create(bufferSize: 2)

replaySubject.onNext("Event 1")
replaySubject.onNext("Event 2")
replaySubject.onNext("Event 3")

// 구독
replaySubject.subscribe(onNext: {
    print("Subscriber 1 received: \($0)")
}).disposed(by: disposeBag)

replaySubject.onNext("Event 4")

// 새로운 구독자 추가
replaySubject.subscribe(onNext: {
    print("Subscriber 2 received: \($0)")
}).disposed(by: disposeBag)

replaySubject.onNext("Event 5")

/// 출력 결과
Subscriber 1 received: Event 2
Subscriber 1 received: Event 3
Subscriber 1 received: Event 4
Subscriber 2 received: Event 3
Subscriber 2 received: Event 4
Subscriber 1 received: Event 5
Subscriber 2 received: Event 5

AsyncSubject

스트림이 완료되었을 때 마지막으로 발생한 이벤트만 전달합니다.
스트림이 완료되기 전까지는 어떠한 이벤트도 전달하지 않음.

// AsyncSubject 생성
let asyncSubject = AsyncSubject<String>()

// 구독
asyncSubject.subscribe(onNext: {
    print("Subscriber 1 received: \($0)")
}).disposed(by: disposeBag)

asyncSubject.onNext("Event 1")
asyncSubject.onNext("Event 2")

// 새로운 구독자 추가
asyncSubject.subscribe(onNext: {
    print("Subscriber 2 received: \($0)")
}).disposed(by: disposeBag)

asyncSubject.onNext("Event 3")
asyncSubject.onCompleted()

/// 출력 결과
Subscriber 1 received: Event 3
Subscriber 2 received: Event 3

0개의 댓글