포스트

RxSwift 연산자 정리 ⑦ - Sharing

Sharing 연산자

Sharing 연산자는 옵저버블이 방출하는 항목을 다른 옵저버와 공유할 수 있는 연산자입니다. 즉, 유니캐스트로 동작하는 옵저버블멀티캐스트로 바꿔줍니다. 불필요한 스트림 낭비를 막고, 메모리 성능을 향상시키기 위해 적재적소에 스트림을 공유하는 게 좋습니다. 대표적인 연산자로 share 연산자가 있습니다.

multicast

메서드설명비고
multicast(_ subject:)이 연산자는 옵저버블이 방출하는 항목을 다른 옵저버와 공유할 수 있습니다.
옵저버블이 방출하는 항목은 옵저버가 아닌 첫 번째 매개변수로 전달하는 서브젝트에 전달됩니다.
이렇게 서브젝트로 전달된 항목이 다시 여러 옵저버에게 방출됩니다.
모든 옵저버를 추가한 이후 connect() 메서드를 호출해주어야 옵저버블이 항목을 방출합니다.
첫 번째 매개변수로 서브젝트를 전달해야 합니다.
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let publishSubject = PublishSubject<Int>()

let source = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
    .take(5)
    .multicast(publishSubject)

source
    .subscribe { print("⭐️: ", $0) }
    .disposed(by: disposeBag)

source
    .delaySubscription(.seconds(3), scheduler: MainScheduler.instance)
    .subscribe { print("✈️: ", $0) }
    .disposed(by: disposeBag)

source.connect()

publish

메서드설명비고
publish()이 연산자는 옵저버블이 방출하는 항목을 다른 옵저버와 공유할 수 있습니다.
multicast 연산자에서는 직접 서브젝트를 만들어 넘겨주어야 했다면, 이 연산자는 자체적으로 PublishSubject를 만들어 multicast 연산자의 매개변수로 전달합니다.
-
1
2
3
4
5
6
7
8
9
10
11
12
let source = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
    .take(5)
    .publish()

source
    .subscribe { print("⭐️: ", $0) }
    .disposed(by: disposeBag)

source
    .delaySubscription(.seconds(3), scheduler: MainScheduler.instance)
    .subscribe { print("✈️: ", $0) }
    .disposed(by: disposeBag)

replay

메서드설명비고
replay(_ bufferSize:)이 연산자는 옵저버블이 방출하는 항목을 다른 옵저버와 공유할 수 있습니다.
multicast 연산자에서는 직접 서브젝트를 만들어 넘겨주어야 했다면, 이 연산자는 자체적으로 ReplaySubject를 만들어 multicast 연산자의 매개변수로 전달합니다.
새로운 옵저버가 구독을 하게 되면 버퍼에 저장된 항목을 모두 방출합니다.
첫 번째 매개변수로 버퍼 사이즈를 전달합니다. (버퍼 사이즈가 0이라면 PublishSubject처럼 동작합니다)
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
let source = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
    .take(5)
    .replay(2)

source
    .subscribe { print("⭐️: ", $0) }
    .disposed(by: disposeBag)

source
    .delaySubscription(.seconds(3), scheduler: MainScheduler.instance)
    .subscribe { print("✈️: ", $0) }
    .disposed(by: disposeBag)

source.connect()

refCount

메서드설명비고
refCount()이 연산자는 새로운 옵저버가 추가되는 시점에 자동으로 connect() 메서드를 호출합니다.-
1
2
3
4
5
6
let source = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
    .take(5)
    .publish()
    .refCount()

source.subscribe { print("✈️: ", $0) }

share

메서드설명비고
share(replay:scope:)이 연산자는 옵저버블이 방출하는 항목을 다른 옵저버와 공유하 수 있습니다.
앞서 살펴본 연산자를 모두 합쳐 편리하게 사용하도록 도와줍니다.
첫 번째 매개변수로 버퍼 사이즈를 전달합니다. (버퍼 사이즈가 0이라면 PublishSubject처럼 동작합니다)
scope 매개변수로 SubjectLifeTimeScope 타입의 버퍼의 생명 주기를 전달합니다.
.whileConnected.forever 중 하나를 전달해야 합니다.
whileConnected는 하나 이상의 옵저버가 존재하는 동안에만 버퍼를 유지합니다.
forever옵저버가 하나도 남아있지 않더라도 버퍼를 유지합니다.
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
let source = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
    .share(replay: 5, scope: .forever)

let ob1 = source
    .subscribe { print("🛠️", $0) }

let ob2 = source
    .delaySubscription(.seconds(3), scheduler: MainScheduler.instance)
    .subscribe { print("✏️", $0) }

DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
    ob1.dispose()
    ob2.dispose()
}

DispatchQueue.main.asyncAfter(deadline: .now() + 7) {
    let ob3 = source.subscribe { print("⭐️", $0) }
    let ob4 = source.subscribe { print("🐬", $0) }
    
    DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
        ob3.dispose()
        ob4.dispose()
    }
}

참고 자료

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.