Subject는 Observable이자 Observer이다.
이벤트를 받으면 그 이벤트를 다시 구독자들에게 전달하는 역할을 한다.
→ 값을 방출할 수 있을 뿐 아니라 Observe도 가능하다!!
Subject에는 Publish Subject, Behavior Subject, Replay Subject, BehaviorRelay등 다양한 종류가 있다.
let subject = PublishSubject<String>()
subject.onNext("Issue 1")
subject.subscribe { event in
print(event)
}
subject.onNext("Issue 2")
subject.onNext("Issue 3")
subject.dispose()
subject.onCompleted()
subject.onNext("Issue 4")
// 실행 결과
next(Issue 2)
next(Issue 3)
Publish Subject는 초깃값 없이 생성되고, 구독한 이후 방출되는 이벤트만 전달받는다.
onNext()
메소드를 사용해서 값을 방출한다.dispose()
메소드를 호출한 후에 호출된 메소드들의 결과는 적용되지 않는다.dispose()
를 호출하지 않고 onCompleted()
만 호출하면 completed가 출력된다.Behavior Subject는 Publish Subject와 비슷하다. 대신 초기화를 할 때 초깃값을 전달해주어야 한다. 구독을 하면 가장 최신 이벤트를 전달받는다.
let disposeBag = DisposeBag()
let subject = BehaviorSubject(value: "Initial Value")
subject.onNext("Last Issue")
subject.subscribe { event in
print(event)
}
subject.onNext("Issue 1")
// 실행 결과
next(Last Issue)
next(Issue 1)
초깃값을 설정한 후 방출된 최신 값이 Last Issue
이므로 Last Issue를 방출하고, 그 다음 Issue 1
이 방출되었기 때문에 Issue 1도 출력된다.
설정한 버퍼 크기만큼의 이벤트를 저장하고, Observer가 구독을 시작하면 버퍼에 있는 모든 이벤트를 전달한다.
let subject = ReplaySubject<String>.create(bufferSize: 2)
subject.onNext("Issue 1")
subject.onNext("Issue 2")
subject.onNext("Issue 3")
subject.subscribe {
print($0)
}
// 실행 결과
next(Issue 2)
next(Issue 3)
버퍼 크기를 2로 설정했기 때문에 가장 마지막으로 방출된 두 개의 이벤트가 전달된 것을 볼 수 있다.
let subject = ReplaySubject<String>.create(bufferSize: 2)
subject.onNext("Issue 1")
subject.onNext("Issue 2")
subject.onNext("Issue 3")
subject.subscribe {
print($0)
}
subject.onNext("Issue 4")
subject.onNext("Issue 5")
subject.onNext("Issue 6")
print("[Subscription 2]")
subject.subscribe {
print($0)
}
첫 번째 subscribe 밑에 3개의 이벤트와 새로운 subscribe 메소드를 하나 추가하고 코드를 실행시키면 아래와 같은 실행결과가 나온다.
next(Issue 2)
next(Issue 3)
next(Issue 4)
next(Issue 5)
next(Issue 6)
[Subscription 2]
next(Issue 5)
next(Issue 6)
두 번째 subscription은 가장 마지막에 방출된 이벤트인 Issue5와 Issue6을 출력한다.
Variable은 behavior subject를 감싸고 있으며, 현재 값의 상태를 저장한다. 이 값은 value
프로퍼티를 사용해서 접근할 수 있다.
let variable = Variable("Initial Value")
variable.value = "Hello world"
variable.asObservable()
.subscribe {
print($0)
}
// next(Hello World)
Variable은 RxSwift에서 공식적으로 deprecated되었다고 한다 😱 대신
BehaviorRelay
나BehaviorSubject
를 사용해야 한다. (참고: What’s New in RxSwift5)
BehaviorRelay는 RxCocoa
를 import해야 사용할 수 있다.
let relay = BehaviorRelay(value: "Initial Value")
relay.asObservable()
.subscribe {
print($0)
}
relay.value = "Hello World" // Error!
relay.accept("Hello World")
BehaviorRelay의 value
는 읽기 전용이기 때문에 값을 직접 수정할 수 없다. 대신 accept()
라는 메소드를 사용해서 새 값을 넣어줄 수 있다.
// 실행 결과
next(Initial Value)
next(Hello World)
BehaviorRelay의 값이 배열이라면 나중에 값을 어떻게 변경해줄 수 있을까?
let relay = BehaviorRelay(value: ["Item 1"])
// 방법 1
var value = relay.value
value.append("Item 2")
value.append("Item 3")
relay.accept(value)
// 방법 2
relay.accept(relay.value + ["Item 2", "Item 3"])
relay.asObservable()
.subscribe {
print($0)
}
value
의 값을 직접 변경해줄 수 없기 때문에 새 변수에 값을 담아서 append 하거나 value
에 저장된 배열과 새 값들을 저장한 배열을 합쳐서 accept 해주는 식으로 저장해주어야 한다.
next(["Item 1", "Item 2", "Item 3"])
BehaviorRelay는 UI에서 사용하기 좋도록 변형된 Subject라고 한다. 더 자세한 차이점 및 사용 방법은 나중에 공부해야 할 듯!