저 위에 그림에 있는 마블 하나하나가 옵저버블이라는 말도 있는데 그림으로 봐선 절대 아니고,
저 선이 파이프라인인 건지 뭔지 처음에는 많이 헷갈렸다.
옵저버블, 파이프라인, 데이터 스트림, 구독 등...
여러 개념들이 헷갈리기도 하고 추상적이기도 해서 정리해 보려 한다.
Rx 공식 예제를 통해 정리해 보겠습니당
그롬 스따뜨
RxSwift 깃허브에서 프로젝트를 다운받고
https://github.com/ReactiveX/RxSwift
Rx.xcworkspace를 실행하고,
RxExample-iOS 선택해서 시뮬레이터로 빌드하면 여러가지 Rx 예제들을 테스트해 볼 수 있당
예시로 두번째 Simple validation을 눌러서 나오는 화면으로 확인해 보쟝
유효성 검사다 흐흐
이 화면 뷰컨을 열어보겠다
RxCocoa 객체들로 짜인 로직이지만, RxCocoa도 결국 RxSwift 기반이고, 기본적인 개념(옵저버블, 구독 등)은 같기에 요걸로 정리해 보겠슴니당
보시면 아시겠지만..
유저네임 텍스트필드와 비밀번호 텍스트필드의 각 값을 유효성 검사하고,
각각 유효한 경우 각 레이블을 가리고,
전부 유효한 경우 버튼까지 활성화하는 흐름이 보입니다.
옵저버블?
Rx의 타입이라고 볼 수 있겠다.
제네릭해서 String, Int 등 여러 타입을 품을 수 있다.
위 뷰컨에서는
`let usernameValid = usernameOutlet.rx.text.orEmpty`
이게 하나의 옵저버블이다.
usernameValid는 사용자가 입력한 사용자 이름의 길이가 minimalUsernameLength보다 긴지 여부를 나타내는 boolean 값을 발행하는 옵저버블이다. 이 옵저버블은 계속해서 변할 수 있고, rx.text.orEmpty를 통해 텍스트가 변경될 때마다 값이 바뀌어 구독자에게 알리게 된다.
마찬가지로
`let passwordValid = passwordOutlet.rx.text.orEmpty`
이것도 하나의 옵저버블이다.
rx를 통해 옵저버블 객체를 만들었다고 보면 된다.
연산자?
`let everythingValid = Observable.combineLatest(usernameValid, passwordValid) { $0 && $1 }`
이것도 하나의 옵저버블인데, `combineLatest` 이 연산자를 사용해서 두 옵저버블(usernameValid와 passwordValid)을 합친 것이다.
let usernameValid = usernameOutlet.rx.text.orEmpty
.map { $0.count >= minimalUsernameLength }
사실 여기 `map`도 연산자다. `usernameOutlet.rx.text.orEmpty`까지는 옵저버블 String인데,
사용자가 입력한 사용자 이름의 길이가 minimalUsernameLength보다 긴지 여부를 나타내는 옵저버블 boolean 값으로 변환하는.
이렇게 ReactiveX에는 옵저버블을 생성하고, 변환하고, 필터링하고, 결합 등등.. 아주 다양한 연산자들이 있다!
그럼 결국 everythingValid도 map 연산자 적용한 옵저버블에다가 combineLatest 연산자도 적용한 거네?그렇다,, Rx에서는 옵저버블에 여러 연산을 결합할 수 있고, 체이닝 방식으로 한 번에도 가능하다!
모든 연산자들은 아래 링크에서 확인할 수 있당
https://reactivex.io/documentation/ko/operators.html
데이터 흐름? 데이터 스트림?
데이터 흐름 = 데이터 스트림stream이 흐름이라는 뜻이기 때문..이다 당연하게도
위에서 한 옵저버블이 map, combineLatest 등 연산자를 만나 변환되는 과정을 거쳤는데,이러한 일련의 과정을 데이터 스트림이라 하고 결국 옵저버블이 데이터 스트림인 것이다.데이터 스트림의 일부분이라고도 볼 수 있지만, 바뀐 결과물도 그 옵저버블이니까..
옵저버블은 결국 변화하는 데이터를 발행하는 스트림이고,이 스트림은 값을 계속해서 publish 할 수 있다. usernameValid는 유저네임 유효 여부, passwordValid는 비밀번호 유효 여부, everythingValid는 유저네임과 비밀번호 둘 다 유효한지의 여부를 publish 하는 것!
그리고 이렇게 퍼블리시된 값은 구독자가 받아 처리한다.구독자는 옵저버블이 발행하는 데이터를 관찰하거나 이에 따라 반응할 수 있다.
파이프라인?
날 가장 헷갈리게 했던 개념이다..ㅎㅎ
그래서 파이프라인이 데이터 스트림이라는 거야 뭐야? 흐름같은데.. 옵저버블 = 데이터 스트림이라며..근데 파이프라인이 옵저버블 자체는 아닌 거 같은데....
파이프라인은 추상적인 개념이다.파이프라인은 여러 연산이나 데이터 스트림을 조합해서, 하나의 처리 흐름을 만드는 방식이다.앞서 Rx에서는 옵저버블을 체이닝 방식으로 여러 연산을 결합할 수 있다고 했는데,이렇게 데이터의 흐름을 설정하는, 여러 연산과 옵저버블이 이어진 구조,...이자 방식이 파이프라인인 것이다..!!
구독?
구독을 하면, 옵저버블이 발행하는 데이터를 관찰하거나 이에 따라 반응할 수 있다.
유튜브에서도 구독하지 않은 채널은 새로운 영상이 올라와도 알림을 받을 수 없죵?하지만 채널(옵저버블)을 구독(subscribe)한 시점부터는 새로운 영상(옵저버블이 발행하는 이벤트나 아이템)이 발행/업로드(publish)될 때마다 우리가 알림을 받을 수 있듯이!!!
이 개념을 유저네임 유효성 부분으로 확인해보쟝.
usernameValid
.bind(to: usernameValidOutlet.rx.isHidden)
.disposed(by: disposeBag)
`bind`라는 연산자를 통해 구독이 발생했다!
`bind`는 옵저버블의 값을 다른 UI 요소나 프로퍼티에 바인딩하는 데 사용된다.
이 바인딩을 통해 데이터 흐름 파이프라인을 구성하게 된다.옵저버블에서 발행한 값을 받아서, 해당 값이 UI나 다른 요소에 자동으로 반영되도록 해 준다.
1. `usernameValid` 옵저버블이 값(`true` 또는 `false`)을 발행한다.
2. `bind`를 통해 그 값이 `usernameValidOutlet.rx.isHidden`에 전달된다.
3. UI 요소의 `isHidden` 상태가 자동으로 업데이트된다.
요 흐름으로 가는 것이닷
usernameValid 옵저버블을 구독하는 부분이 하나 더 있는데,
usernameValid
.bind(to: passwordOutlet.rx.isEnabled)
.disposed(by: disposeBag)
여기서는 닉네임이 유효하면, 패스워드 텍스트필드가 활성화되는구나~ 를 알 수 있죵!!!!
누가 누구를 구독하는 건지 다시 정리하자면,
`passwordOutlet.rx.isEnabled`가 `usernameValid`옵저버블을 구독한다.
- `usernameValid`는 텍스트 필드의 길이를 확인하여 `true` 또는 `false` 값을 발행하는 옵저버블이다.
- `bind(to:)`는 `usernameValid`의 발행 값을 구독하고 그 값을 다른 프로퍼티에 전달하는 역할을 한다.
- 여기서 `passwordOutlet.rx.isEnabled`은 구독자(Subscriber) 역할을 한다.
즉, `usernameValid` 옵저버블이 발행하는 값(`true` 또는 `false`)을 구독하고, 그 값을 `passwordOutlet`의 `isEnabled` 프로퍼티에 반영한다.
→ bind를 사용하면 옵저버블과 UI 요소 간의 연결을 설정하는 파이프라인을 만들 수 있다.
구독은 파이프라인의 마지막 단계로 볼 수 있다.
옵저버블을 구독하면 실제로 데이터를 받게 되고, 그 데이터가 파이프라인을 따라 흐르면서 연산자들이 그 데이터를 처리하게 된다. 구독은 파이프라인을 실행하는 동작이지만, 데이터의 흐름을 "받는" 역할이기 때문에 파이프라인 자체라기보다는 파이프라인의 결과를 받아 처리하는 마지막 단계라고 할 수 있다.
만약 옵저버블에 다른 연산은 하지 않고 바로 구독을 했다면..?
파이프라인을 구성하면서 마지막 완성을 했다 이런 느낌으로 받아들일 수 있을 것 같다.
파이프라인 2
usernameValid만 봐도,combineLatest로 결합되는 파이프라인, 유저네임 유효성 label에 바인딩되는 파이프라인비밀번호 텍스트필드에 바인딩되는 파이프라인이렇게 여러 개가 생겼다.
결국 옵저버블 하나에 여러 파이프라인이 생길 수 있는 것이다!
결론
- 옵저버블은 값의 흐름을 나타내는 객체다.
- 파이프라인은은 여러 옵저버블이나 연산을 연결하여 데이터의 흐름을 만들어내는 방식이다.
- 옵저버블 ≠ 파이프라인
- 옵저버블은 파이프라인에서 중요한 역할을 하는 데이터 흐름의 한 부분
- 옵저버블 하나에 여러 파이프라인을 만들 수 있다
- 구독을 하면, 옵저버블이 발행하는 데이터를 관찰하거나 이에 따라 반응할 수 있다
하 생각보다 텍스트가 넘 많아졌는데 ^_ ㅠ ..
누군가에게.. 그리고 미래의 나에게 도움이 되길.. (미래의 나는 다시 이걸 안 봐도 되길..)