RxSwift 기초 2편 - dispose/subject
구독 취소 disposing
우리가 무언가를 subscribe하기 시작하면 해당 subscribe는 value의 변동을 '항상' listening 상태로 둔다.
그 수가 많아지면 아무래도 메모리 측면에서 비효율을 야기할 것이다.
그러니 구독을 취소하는 방법도 배워보자.
기본형
예를 들어 다음과 같은 subscription1이 있다고 할 때, subscriber를 dispose하는 방법은 단순히 .dispose()
를 원하는 시점에 호출하는 것 뿐이다.
// subscription1을 Subscriber라고 한다.
let subscription1 = observable4.subscribe(onNext: { (event) in
print(event)
})
// dispose를 통해 memory leak을 방지.
subscription1.dispose()
이렇게 함으로써 개발자는 메모리 관리를 의도한 대로 할 수 있다.
disposeBag
그런데 일일이 subscriber들을 dispose하는 것은 개발자 입장에서 충분히 까먹고 지나칠 수 있는 일이다.
이 때 우리는 disposeBag이라는 것을 사용할 수 있는데,
disposeBag은 그것을 위해 subscriber들의 Observing을 "적절한 때에" dispose하는 데에 쓰인다.
사용형식은 다음과 같다.
disposeBag을 생성하고, subscriber가 disposed(By: disposeBag)
을 호출하면 된다.
// bag 생성
let disposeBag = DisposeBag()
// 이 disposeBag은 .disposed(by: ) 메소드와 함께 쓸 수 있다.
// 아래는 subscribe하는 것과 동시에 disposeBag에 해당 subscription의 dispose를 넣는 예제이다.
Observable.of("A", "B", "C")
.subscribe {
print($0)
}.disposed(by: disposeBag)
예제를 하나만 더 살펴보자.
Observable을 생성함과 동시에 subscribe도 하고,
observable, subscribe이 생성되는 시점에 실행될 함수도 넣으면서
dispose까지 한번에 해보자.
아래는 그 예시이다.
Observable<String>.create { (observer) in
observer.onNext("A")
observer.onCompleted()
observer.onNext("?")
// create 메소드는 아래처럼 disposable을 리턴해줘야 한다.
return Disposables.create()
}.subscribe(onNext: {print ($0)},
onError: {print($0)},
onCompleted: {print("OnCompleted")},
onDisposed: {print("disposed")})
.disposed(by: disposeBag)
/*
completed
A
OnCompleted
disposed
// ?는 출력되지 않았다. onCompleted 이후 코드는 실행되지 않는다.
*/
Subject
RxSwift에서 배워야 할 개념 중 하나로 Subject라는 것도 있다.
중요하고 흥미로운 개념이니 잘 이해하고 넘어가자.
특징
Subject는 Obeserver와 똑같이 observable
하다는 특징을 갖는다.
Subject는 Event를 받아서 Subscriber에게 그것을 전달하는 역할을 한다.
PublishSubject
PublishSubject는 subscribe할 수 있고, event를 전달해주는 대표적인 subject이다.
사용 형식
let subject = PublishSubject<String>()
subject.onNext("Issue #1") // 첫 번째 이슈가 발행됐다고 가정.
subject.subscribe { (event) in
print(event)
}
// 이 시점엔 아무것도 출력되지 않음.
subject.onNext("Issue #2") // 두 번째 이슈가 발행됐다고 가정.
// next(Issue #2)가 출력됨.
subject.onNext("Issue #3")
// next(Issue #3) dispose()
subject.dispose()
subject.onCompleted()
//아무것도 출력되지 않음.
publishSubject는 가장 기본적인 형태의 subject이다.
다른 목적에 맞게 subject는 몇 가지 유형이 더 있는데, 한번 살펴보자.
BehaviorSubject
BehaviorSubject는 초기값을 지정할 수 있다.
예를 들어 아래처럼 "Issue #1" 같은 초기값을 지정할 수 있다는 소리다.
초기값은 subscribe시 읽을 수 있다.
예제
// initialValue를 요구.
let behaviorSubject = BehaviorSubject(value: "Issue #1")
behaviorSubject.subscribe { event in
print(event)
}
behaviorSubject.onNext("Issue #2")
// 1, 2가 모두 출력됨.
// next(Issue #1)
// next(Issue #2)
RelaySubject
RelaySubject는 따로 버퍼 사이즈를 지정해줘야 한다.
이 버퍼사이즈는 subscribe 하는 시점에
사용되는데,
해당 시점에 버퍼 사이즈 만큼 최신에
발행된 event를 가져온다.
stack과 같이 LIFO이다.
// 버퍼 사이즈를 지정해줘야 하는 subject.
// `subscribe 시점에` 버퍼 사이즈 만큼 최신에 발행된 onNext event를 가져옴.
let replaySubject = ReplaySubject<String>.create(bufferSize: 2)
replaySubject.onNext("Issue #1")
replaySubject.onNext("Issue #2")
replaySubject.onNext("Issue #3")
replaySubject.subscribe { event in
print(event)
}
// 출력:
// next(Issue #2)
// next(Issue #3)
replaySubject.onNext("Issue #4")
replaySubject.onNext("Issue #5")
replaySubject.onNext("Issue #6")
print("[ReplaySubscription 2]")
replaySubject.subscribe { event in
print(event)
}
// 출력:
// [ReplaySubscription 2]
// next(Issue #5)
// next(Issue #6)
BehaviorRelay
BehaviorRelay는 어떤 변수를 생성하고, 그것을 Observable하게 만들 때 쓰인다.
원래는 Variable이라는 자료형을 제공했으나, Variable은 곧 deprecate될 예정이다.
초기값을 지정해야 하고, RxCocoa
를 요구한다.
따라서 podfile에 pod 'RxSwift', '~> 4.0'
을 적어주고 pod install로 설치한 후 import까지 해준다.
예제
BehaviorRelay는 만듦과 동시에 subscribe할 수 있으며, .accept로 값을 대치
할 수 있다.
import RxSwift
import RxCocoa
// relay는 어떤 변수를 생성하고 그것을 Observable하게 만들 때 쓰인다.
// 초기값을 지정해주어야 한다.
// BehaviorRelay는 RxCocoa가 pod install 되어 있어야 한다.
let relay = BehaviorRelay(value: "This is Initial Value")
// 생성한 변수`.asObservable()` 을 이용해 observable로 만들 수 있다.
// 만듦과 동시에 .subscribe로 구독할 수 있다.
relay.asObservable()
.subscribe {
print ($0)
}
// 변수의 값을 accept로 변경하는 법:
relay.accept("Hello World")
/* 여기까지 실행 시 출력문:
next(This is Initial Value)
next(Hello World)
*/
예제2 - value 추가하기.
.accept는 값을 대치
하지만 값의 추가
가 필요할 때도 있을 것이다.
그것은 value를 받아오고 value에 값을 추가한 뒤 .accept(value) 함으로써 가능하다.
코드로 살펴보자.
// array자료형을 추가할 수도 있다.
// 아래는 emptyArray를 추가하는 예제.
//let relayArray = BehaviorRelay(value: [String]())
// 초기화하면서 변수를 생성.
let relayArray = BehaviorRelay(value: ["Item 0"])
relayArray.asObservable()
.subscribe {
print ($0)
}
/*출력
next(["Item0"])
*/
// Array의 값을 '대치'하는 것은 다음과 같이 가능하다.
relayArray.accept(["Item 1"])
/*출력
next(["Item1"])
*/
// 값을 이어 붙이고 싶을 때:
var value = relayArray.value
value.append("item 2")
value.append("item 3")
relayArray.accept(value)
/*출력
next(["Item1", "item2", "item3"])
*/
'iOS::스위프트(swift) > RxSwift+MVVM' 카테고리의 다른 글
RxSwift 기초 5 - Combining Operators (0) | 2021.06.08 |
---|---|
RxSwift 기초 4 - Operator Transforming (0) | 2021.06.07 |
RxSwift 기초 3 - 필터링(Filtering Operators) (0) | 2021.05.25 |
RxSwift 기초 - observable과 subscribe (0) | 2021.05.17 |
swift MVVM 정리 및 예제 (8) | 2021.03.28 |
최근댓글