안녕하세요. iOS 개발자 JHM입니다.
이번 글을 시작으로 제가 스터디 했던 RxSwift 내용을 블로그로 공유드리려고 합니다. 공유하려는 이유는 RxSwift를 첫 입문했던 시절 영어 레퍼런스, RxSwift의 어려운 개념 등의 허들에 막혀서 헤매었던 기억이 남아있어, 다른 입문자 분들에게 도움이 되고 싶기 때문입니다.
제가 RxSwift를 좀 더 깊게 공부하고 싶어서 많은 시도를 해보았을 때, 가장 도움이 되었던 방법은 RxSwift에서 제공해주는 Playground를 분석하는 것이 었습니다.
앞으로의 블로그 글을 통해 제가 어떤 분석을 하면서 RxSwift의 이해도를 높여왔는지 말씀드리겠습니다.
오늘은 RxSwift를 만든 이유와 간단한 동작 원리를 설명한 "Introduction" 파트를 파헤쳐보겠습니다.
# 영어 원문과 (갓)구글 번역한 내용과 함께 필요한 부분에서 제가 이해한 부분을 전달드리는 패턴으로 글을 계속 써갈 생각입니다.
예시)
- I LIKE APPLE! (Playground 원문)
- 사과 좋아! (구글 번역)
: 진짜 사과와 애플을 모두 좋아한다는 뜻입니다. (해설)
Introduction Part1 (Why use RxSwift)
- A vast majority of the code we write involves responding to external events. When a user manipulates a control, we need to write an @IBAction handler to respond. We need to observe notifications to detect when the keyboard changes position. We must provide closures to execute when URL sessions respond with data. And we use KVO to detect changes to variables. All of these various systems makes our code needlessly complex. Wouldn't it be better if there was one consistent system that handled all of our call/response code? Rx is such a system.
- 우리가 쓰는 대부분의 코드는 외부 이벤트에 대한 응답을 포함합니다. 예를 들면, 사용자의 디바이스 컨트롤을 조작하기 위해서, 우리는 IBAction 핸들러를 작성하여 사용합니다. 또, 우리는 키보드의 위치의 변화 탐지에 대한 알림을 관찰해야 할 필요도 있습니다. 또, 우리는 URL Session의 응답 결과 Data를 실행하는 closure를 제공해야 합니다. 그리고, 변수의 변화를 탐지하기 위해 KVO (Key-Value Observing)를 사용합니다. 이러한, 외부 이벤트에 대응해야 하는 종류는 다양하기에, 우리의 코드릴 필요 이상으로 복잡하게 만듭니다. 우리의 모든 호출 / 응답 (외부 이벤트에 대한) 일관되게 처리하는 시스템이 있다면 좋지 않을까? Rx가 그런 시스템입니다.
: iOS를 개발하면서 만나는 다양한 외부 이벤트(IBAction, Keyboard Input, URLSession, KVO) 처리는 정말 다양한 패턴(Delegate, Closure, Observer Pattern)을 보입니다. RxSwift는 이런 다양한 패턴을 통일화하여 단순하면서 빠른 개발 환경을 만들기 위해 생생된 시스템입니다.
Introduction Part2 (RxSwift Concept)
1. Observable 설명
- Every Observable instance is just a sequence. The key advantage for an Observable sequence vs. Swift's Sequence is that it can also receive elements asynchronously.
- 모든 Observable은 단순한 Sequence 입니다. (Sequence란 동일한 Type에 대한 순차적이고 반복적인 액세스를 제공하는 형식입니다. 배열을 생각하시면 됩니다.) Observable의 장점은 item(element)을 비동기적으로 받아들인다는 점입니다.
: RxSwift는 Sequence와 같이 동일한 Type의 item을 반복적으로 제공하는 Observable을 사용합니다. 다만, Sequence와의 차이는 Observable은 비동기적으로 item들을 제공한다는 점입니다. RxSwift의 비동기를 설명하기 위해 다음 코드를 보겠습니다.
for item in ["a","b","c","d"] {
print(item)
}
let 외부이벤트예시 = PublishSubject<String>()
Observable.of(외부이벤트예시)
.subscribe(onNext: {
print($0) // 2 // 4
// 🅰️ 🅱️
})
외부이벤트예시.onNext("🅰️") // 1
외부이벤트예시.onNext("🅱️") // 3
( ⚠️ 예시 코드를 너무 깊게 고민하진 마세요! 비동기 내용 파악에 집중하셔야 합니다 )
i) for 구문(Sequence)은 모든 Item을 print 해야 다음 코드를 실행할 수 있습니다. 즉, "a", "b", "c", "d"를 전부 방출해야 다음 코드를 해석할 수 있습니다.
ii) 제가 작성한 Observable 구문을 보면, print를 하는 closure를 이미 위에 선언되어있지만, 어떤 동작도 하지 않습니다. 하지만, 외부 이벤트를 통해 Item이 발생했을 때에 closure가 동작합니다. 이렇게, 코드의 선언과 실행이 다른 것을 비동기적이라고 합니다.
2. Observable 구조 설명 (observer 및 Item 종류 등장)
- An Observable (ObservableType) is equivalent to a Sequence. The ObservableType.subscribe(_:) method is equivalent to Sequence.makeIterator(). ObservableType.subscribe(_:) takes an observer (ObserverType) parameter, which will be subscribed to automatically receive sequence events and elements emitted by the Observable, instead of manually calling next() on the returned generator.
If an Observable emits a next event (Event.next(Element)), it can continue to emit more events.However, if the Observable emits either an error event (Event.error(ErrorType)) or a completed event (Event.completed), the Observable sequence cannot emit additional events to the subscriber.
- Observable(ObservableType)은 Sequence와 동일합니다. Observable.subscribe는 Sequence.makeIterator와 동일합니다. subscribe를 실행하면, Observable가 방출하는 item을 자동으로 읽는 observer를 내부에서 획득합니다.
방출한 item이 next() 이벤트라면 다음에도 또 다른 item을 받을 수 있습니다. 하지만, 방출된 item이 error/completed 이벤트라면, Observable은 더 이상 추가적인 이벤트를 구독자에게 방출할 수 없습니다.
: RxSwift의 구조가 거의 다 보인 것 같습니다. Observable은 item(next/error/completed)을 뱉어내는 비동기 Sequence이며, Observable과 짝을 이루는 observer(관찰자)는 Observable이 뱉어낸 item을 읽어 들이는 역할을 합니다. Observable의 subscribe 실행하면 observer가 Observable의 Item을 획득하기 시작합니다.
각 Item(Event)의 종류를 간단하게 표로 보겠습니다.
Item(Event) Type | 다음 Item 발생 유무 | 역할 |
next | O | 처리해야하는 값을 observer에게 전달하는 역할 |
error | X | Item 생성 중 발생한 Error를 observer에게 전달하는 역할 |
completed | X | 모든 값들이 발생하고 끝났다라는 정보를 observer에게 전달하는 역할 |
이제부터 "Observable이 발생시킨 Item"라는 표현을 "Observable이 발생시킨 Event"라고 표현하겠습니다.
3. Observable과 observer
- Observables will not execute their subscription closure unless there is a subscriber. In the following example, the closure of the Observable will never be executed, because there are no subscribers
In the following example, the closure will be executed when subscribe(_:) is called
- Observable은 구독자가 존재하지 않으면, 그들의 구독에 대한 closure(subscribe의 클로저)를 절대 시행하지 않습니다.
example("Observable with no subscribers") {
_ = Observable<String>.create { observerOfString -> Disposable in
print("This will never be printed")
observerOfString.on(.next("😬"))
observerOfString.on(.completed)
return Disposables.create()
}
}
// observer를 불러내는 subscribe가 존재하지 않아서 아무 이벤트가 발생하지 않습니다.
example("Observable with subscriber") {
_ = Observable<String>.create { observerOfString in
print("Observable created")
observerOfString.on(.next("😉"))
observerOfString.on(.completed)
return Disposables.create()
}
.subscribe { event in
print(event)
}
}
// subscribe를 진행하였고, observer가 전달한 Item을 print하고 있습니다.
: subscribe가 실행되지 않으면, observer는 Observable의 Event를 받을 수 없는 구조입니다. 따라서, subscribe가 실행되어야 observer가 Observable의 Event를 받아들이고 subscribe의 closure가 동작합니다.
SUMMARY
- RxSwift는 다양한 외부 이벤트(IBAction, Keyboard Input, URLSession, KVO)를 공통된 패턴으로 처리하기 위한 라이브러리이다.
- Observable은 Event를 만들어내는 비동기 Sequence이며, Observable 내부의 observer라는 대상은 subscribe가 실행되면, Observable의 Event를 계속 받게 됩니다. observer가 받은 이벤트는 subscribe의 closure 안에서 처리됩니다.
어려운 문장이나 수정이 필요한 부분
더 다뤄주었으면 하는 부분
에 대해서는 댓글 남겨주시면 정성껏 답변 남기겠습니다.
'RxSwift' 카테고리의 다른 글
RxSwift Playground 파헤치기2 - Operator (feat. startWith) 구조 파악하기 (0) | 2021.04.04 |
---|---|
RxSwift 사용기 (0) | 2019.08.30 |