Mastering RxSwift 3강: Subjects

sanghee·2021년 10월 19일
0

🧠RxSwift

목록 보기
2/3
post-thumbnail

Udemy에서 Mastering RxSwift in iOS 수업을 듣고 난 후 정리한 글입니다.

Section 3: Subjects

3-1. Subjects?

  • newspaper과 비슷하다.
  • 이벤트를 받아서 구독자에게 이슈를 알려준다.

3-2. Publish subjects

  1. String 타입의 subject 신문을 출판하였다.
  2. 신문에 이슈1을 추가하였다.
  3. 구독을 추가하였다.
  4. 신문에 이슈2를 추가하였다.

이슈1은 구독 전에 추가한 것이므로 출력되지 않는다.

let publishSubject = PublishSubject<String>()

publishSubject.onNext("Issue 1")

publishSubject.subscribe { event in
    print(event)
}

publishSubject.onNext("Issue 2")
출력: next(Issue 2)

subject.dispose()

dispose는 사전적 의미로 처분하다를 의미한다. 직관적으로 버리다라고 작성하겠다.

dispose하고 이슈4를 추가하였기 때문에, 이슈4는 출력되지 않는다.

publishSubject.onNext("Issue 1")

publishSubject.subscribe { event in
    print(event)
}

publishSubject.onNext("Issue 2")
publishSubject.onNext("Issue 3") 
       
publishSubject.dispose()
        
publishSubject.onNext("Issue 4")
출력: next(Issue 2)
출력: next(Issue 3)

subject.onCompleted()

subject를 완료하면 완료 이벤트까지 출력된다. 마찬가지로 이슈4는 출력되지 않는다.

만약 dispose한 이후에 onCompleted를 하게 되면, subject는 이미 버렸기에 완료 이벤트는 출력되지 않는다.

publishSubject.onNext("Issue 1")

publishSubject.subscribe { event in
    print(event)
}

publishSubject.onNext("Issue 2")
publishSubject.onNext("Issue 3") 
       
publishSubject.onCompleted()
        
publishSubject.onNext("Issue 4")
출력: next(Issue 2)
출력: next(Issue 3)
출력: completed

3-3. Behavior subjects

behaviorSubject를 만들고 구독하며 이벤트를 출력한다. 처음 값이 출력된다.

let behaviorSubject = BehaviorSubject(value: "Initial value")

behaviorSubject.subscribe { event in
    print(event)
}

behaviorSubject.onNext("Issue 1")
출력: next(Initial value)
출력: next(Issue 1)

기본 값이 Initial value에서 Issue0으로 바뀌었기 때문에, Issue0이 출력된다.

let behaviorSubject = BehaviorSubject(value: "Initial value")

behaviorSubject.onNext("Issue -1")
behaviorSubject.onNext("Issue 0")

behaviorSubject.subscribe { event in
    print(event)
}

behaviorSubject.onNext("Issue 1")
출력: next(Issue 0)
출력: next(Issue 1)

3-4. Replay subjects

replaySubject에서 bufferSize를 2로 설정하였기 때문에

  • 첫번째 구독 → 마지막으로 들어간 두 개의 이슈2와 이슈3이 출력된다. 그리고 이후에 추가된 이벤트들이 출력된다.
  • 두번째 구독 → 마지막으로 들어간 이슈5와 이슈6이 출력된다.
let replaySubject = ReplaySubject<String>.create(bufferSize: 2)

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

replaySubject.subscribe {
    print("첫번째 구독 == \($0)")
}

replaySubject.onNext("Issue 4")
replaySubject.onNext("Issue 5")
replaySubject.onNext("Issue 6")

replaySubject.subscribe {
    print("두번째 구독 == \($0)")
}
출력: 첫번째 구독 == next(Issue 2)
출력: 첫번째 구독 == next(Issue 3)
출력: 첫번째 구독 == next(Issue 4)
출력: 첫번째 구독 == next(Issue 5)
출력: 첫번째 구독 == next(Issue 6)

출력: 두번째 구독 == next(Issue 5)
출력: 두번째 구독 == next(Issue 6)

3-5. Variables

[DEPRECATED] `Variable` is planned for future deprecation. Please consider `BehaviorRelay` as a replacement. Read more at: [https://git.io/vNqvx](https://git.io/vNqvx)

Variable은 곧 사라지기에 아래의 BehaviorRelay를 써야 한다.

value: String

변수를 만들고, 변수의 value를 변경한 후 구독하였다.

let variable = Variable("Initial value")

variable.value = "Hello World"

variable.asObservable().subscribe {
    print($0)
}
출력: next(Hello World)

value: [String]

변수를 String 배열로 설정하였다.

let variableArr = Variable([String]())
  1. value 베열에 아이템1을 추가하였을 때, 아이템1이 출력된다.
  2. 아이템2를 추가하였을 때 배열에 기존에 있던 아이템1과 2가 출력된다.
variableArr.value.append("Item 1")

variableArr.asObservable().subscribe {
    print($0)
}

variableArr.value.append("Item 2")
출력: next(["Item 1"])
출력: next(["Item 1", "Item 2"])

3-6. BehaviorRelay

위의 Variable은 곧 사라지기에 BehaviorRelay를 써야 한다.

시작하기에 앞서 RxCocoa를 불러온다.

import RxCocoa

value: String

3-5. Variables에서 Value 대신 BehaviorRelay를 사용하면 된다. 단 relay의 value를 변경할 때에는 기존처럼 하면 에러가 발생한다(relay에서 value는 get만 가능한 속성이기 때문). 대신 accept를 사용한다.

let relay = BehaviorRelay(value: "Initial value")

relay.asObservable().subscribe {
    print($0)
}

relay.value = "Hello World" // 에러: 'value' is a get-only property
relay.accept("Hello world")
출력: next(Hello World)

value: [String]

위와 같이 relay가 string타입일 때는 accept로 value를 추가하였다. 하지만 relay가 배열 타입일 때는 어떻게 추가해야 할까?

  1. 처음에는 초기값인 아이템0이 출력된다.

  2. ["Item 1"] 배열 자체를 덮어씌운다. 기존 값은 없어진다.

  3. 1의 방법은 좋지 않다. 기존의 value에 아이템2를 추가한 후 설정한다.

  4. value라는 변수에 할당하여 아이템3을 추가한 후 설정한다.

let relayArr = BehaviorRelay(value: ["Item 0"])

// 1
relayArr.accept(["Item 1"])

// 2
relayArr.accept(relayArr.value + ["Item 2"])

// 3
var value = relayArr.value
value.append("Item 3")
relayArr.accept(value)
0출력: next(["Item 0"])
1출력: next(["Item 1"])
2출력: next(["Item 1", "Item 2"])
3출력: next(["Item 1", "Item 2", "Item 3"])

전체 코드

import UIKit
import RxSwift
import RxCocoa

class ViewController: UIViewController {
    let publishSubject = PublishSubject<String>()
    
    let behaviorSubject = BehaviorSubject(value: "Initial value")
    
    let replaySubject = ReplaySubject<String>.create(bufferSize: 2)
    
    let variable = Variable("Initial value")
    let variableArr = Variable([String]())
    
    let relay = BehaviorRelay(value: "Initial value")
    let relayArr = BehaviorRelay(value: ["Item 0"])
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        
        publish()
        behavior()
        replay()
        variableValue()
        variableValueArr()
        behaviorRelay()
        behaviorRelayArr()
    }
}

private extension ViewController {
    func behaviorRelayArr() {
        relayArr.asObservable().subscribe {
            print($0)
        }
        
        relayArr.accept(["Item 1"])
        
        relayArr.accept(relayArr.value + ["Item 2"])
        
        var value = relayArr.value
        value.append("Item 3")
        
        relayArr.accept(value)
    }
    
    func behaviorRelay() {
        relay.asObservable().subscribe {
            print($0)
        }
        
//        relay.value = "Hello World" 에러: 'value' is a get-only property
        relay.accept("Hello world")
    }
    
    func variableValueArr() {
        variableArr.value.append("Item 1")
        
        variableArr.asObservable().subscribe {
            print($0)
        }
        
        variableArr.value.append("Item 2")
    }
    
    func variableValue() {
        variable.value = "Hello world"
        
        variable.asObservable().subscribe {
            print($0)
        }
    }
    
    func replay() {
        replaySubject.onNext("Issue 1")
        replaySubject.onNext("Issue 2")
        replaySubject.onNext("Issue 3")
        
        replaySubject.subscribe {
            print("첫번째 구독 == \($0)")
        }
        
        replaySubject.onNext("Issue 4")
        replaySubject.onNext("Issue 5")
        replaySubject.onNext("Issue 6")
        
        replaySubject.subscribe {
            print("두번째 구독 == \($0)") // next(Issue 5), next(Issue 6)
        }
    }
    
    func behavior() {
        behaviorSubject.onNext("Issue -1")
        behaviorSubject.onNext("Issue 0")
        
        behaviorSubject.subscribe { event in
            print(event) // next(Issue 0)
        }
        
        behaviorSubject.onNext("Issue 1")
    }
    
    func publish() {
        publishSubject.onNext("Issue 1")
        
        publishSubject.subscribe { event in
            print(event)
        }
        publishSubject.onNext("Issue 2") // next(Issue 2)
        publishSubject.onNext("Issue 3") // next(Issue 3)
        
        publishSubject.dispose()
        publishSubject.onCompleted() // 출력 X
        
        publishSubject.onNext("Issue 4") // 출력 X
    }
}
profile
👩‍💻

0개의 댓글