맨날 정리해야지... 생각만 하고 있다가 이제야 정리하게 되네요 하하
RxSwift... 자주 들어보셨죠? 특히 회사 공고에 우대사항에 자주 보일 정도로 중요한 기술입니다.
사실 직접 써보면 여러가지 이점이 많아서 계속 쓰게 됩니다.
오늘은 완전 자세히가 아니라 맛보기 수준으로 정리를 하려고 합니다! (이해가 목적!)
더 깊이 있는 내용들은 다음 시간에 이어서 다룰게요!
Rx(ReactiveX)?
ReactiveX 홈페이지에 들어가면 이런 문구를 볼 수 있습니다!
ReactiveX는 관찰 가능한 흐름들로 비동기적인 프로그래밍을 하기 위한 API다!
음... 사실 저는 처음 Rx를 접할 때 무슨 소리인지 이해를 할 수 없었습니다... 이 부분은 아래에서 다시 설명할게요!
RxSwift는 새로운 언어가 아니라,
Swift 전용 Rx로, Swift에서 Reactive Programming을 할 수 있도록 도와주는 도구입니다!
그렇기 때문에 RxJava, RxKotlin등 다양하게 사용할 수 있습니다.
또 새로운 단어가 나왔네요!
Reactive(반응형) Programming이라...
우선 패러다임에 대해 알면 좋을 것 같습니다.
패러다임의 정의는 한 시대의 사람들의 견해나 사고를 근본적으로 규정하고 있는 인식의 체계. 또는, 사물에 대한 이론적인 틀이나 체계입니다.
간단히 말해서
프로그래밍 패러다임! 이라고 하면, 어떤 것을 중요하게 보고 프로그래밍을 할 것인가! 정도로 이해하시면 될 것 같습니다.
객체지향 프로그래밍이다 -> 객체를 중점으로 프로그래밍을 하겠다! 이런 느낌이죠
그렇다면 반응형 프로그래밍은?
비동기적 데이터 흐름의 추적이 중요합니다!
그래도 어렵죠?
우선 동기와 비동기에 대해서 잠깐 알고 갑시다!
사각형은 어떠한 작업을 나타냅니다.
동기를 보면 앞의 작업이 끝나야 다음 작업을 시작하고 있고,
반대로 비동기는 앞의 작업과 상관 없이 동시에 수행되고 있습니다!
동기는 대기를 해야한다는 단점이 있지만, 앞의 작업이 끝났다는 것을 보장할 수 있습니다. (다음 작업을 수행한다 = 앞의 작업이 종료되었다)
그렇기 때문에 작업의 결과를 처리하기 쉽다는 장점이 있습니다.
비동기는 그 반대겠죠?
대기하지 않고 바로 수행할 수 있지만, 각각의 작업이 끝났을 때 결과를 처리하기 어렵다는 단점이 있습니다.
게다가 설계하기도 어려워요...
이런 비동기 처리를 조금 더 쉽게 할 수 있도록 도와주는 것이 바로 Rx입니다! (Swift에서 도와주니까 RxSwift!)
코드 맛보기
그런데 아직 어떤 장점이 있는가! 얼마나 편한가!를 알기 어렵죠
간단한 예제를 보여드리겠습니다. (코드를 이해하는 것이 아니라 얼마나 간단해지는가!를 중점적으로 봐주세요!)
우선 일반적으로 버튼을 생성하고 탭 이벤트를 넣어주는 코드입니다.
이번엔 Rx를 사용한 코드입니다.
뭔가 느낌이 조금 오시나요?
개인적으로 느꼈던 것은, Rx를 사용하면 처음 접하더라도 이야기를 읽듯이 읽을 수 있다는 것이었습니다. (저만 느꼈다면 죄송합니다...)
마치 체인처럼 .을 계속 사용해서 코드가 간결해지고 가독성이 좋아진다는 장점이 있습니다!
다른 예제를 보여드릴게요
익숙한 코드죠?
테이블뷰에 데이터소스와 델리게이트를 연결해주는 코드입니다.
이 코드 대신 Rx를 사용하면...!
허억
이렇게나 간단해집니다!
Keyword
Rx에서 중요한 친구들이 있습니다.
- Observer (관측자)
- Observable (관측 가능한)
- Subscribe (구독)
이 세 가지 키워드를 합치면 한 개의 문장을 만들 수 있겠죠!
"관측자는 관측 가능한 것을 구독한다."
여기에 한 가지를 더 추가하면
"관측자는 관측 가능한 것이 방출하는 이벤트에 반응한다."
네, 이게 Rx의 일반적인 흐름입니다!
그래도 아직 느낌이 잘 안 오실거에요...
이해를 돕기 위해 Rx의 흐름을 요리에 비유해 보겠습니다! (아주 정확하지는 않지만 도움이 될 것 같습니다 허허)
세상에 공짜는 없습니다. 구독(Subscribe)을 하려면 메모리를 사용해야 하죠!
메모리를 사용했다면 구독이 끝난 후에는 메모리를 해제해줘야 누수가 발생하지 않겠죠?
이렇게 메모리에서 해제하는 것(구독을 종료)을 Dispose라고 부릅니다.
옵저버블이 Disposed되면 더 이상 이벤트를 방출하지 않습니다!
Subscribe (+ emit)
위에서 주문하는 사람이 없으면 요리를 하지 않는다고 했죠?
이 말을 Rx에 대입해보면,
옵저버블은 자신을 구독하는 옵저버에게 이벤트를 방출(Emit)한다!
즉, 구독을 하지 않으면 당연히 이벤트를 받을 수 없겠죠.
Subscribe는 옵저버블과 옵저버를 연결시켜주는 역할을 한다고 보시면 됩니다!
Observable
옵저버블 클래스를 살짝 구경합시다
제네릭으로 Element 타입을 받고 있고... 저기 subscribe 메소드도 보입니다!
옆에 제네릭으로 ObserverType을 사용하고 있는데, 이것도 한 번 확인해 봅시다.
ObserverType은 프로토콜이었네요!
on이라는 메소드가 있고, 파라미터로 Event를 받고 있습니다.
Extension으로 세 가지 메소드를 만들어 놨네요
이 세 가지 메소드가 바로 Subscribe를 하면 받을 수 있는 이벤트들 입니다!
이 이벤트들이 어떤 역할을 하냐면...
- onNext : Element를 순서대로 방출합니다.
- onCompleted : 모든 값(Element)들을 방출하면 이 이벤트를 방출하고 구독을 종료합니다.
- onError : 값을 방출하는 도중 에러가 발생한다면 이 이벤트를 방출하고 구독을 종료합니다.
onCompleted와 onError는 방출된 후에 구독을 종료하는데, 그 후 자동으로 Disposed(메모리에서 해제)됩니다!
또한 이 두 이벤트 중 한 개의 이벤트만 방출됩니다.
당연한 소리죠? 성공 혹은 실패만 발생할테니!
블로그나 유튜브 등에서 옵저버블, 스트림, 시퀀스라는 단어를 사용하는데,
같은 의미로 생각하시면 됩니다!
기본적인 사용은 이렇습니다!
.disposed() 메소드를 사용해서 dispose 시킬 수 있습니다.
dispose의 자세한 설명은 아래에서 할게요!
각 이벤트들의 디폴트 값이 nil이기 때문에 필요한 이벤트만 쏙쏙 골라서 사용하실 수 있습니다!
Disposable
아까부터 Dispose라는 단어를 자주 접했죠?
우선 Subscribe를 다시 보면
구독을 하고 나면 이렇게 Disposable이라는 것을 리턴합니다!
처분할 만한, 사용후 버리게 되어있는 등... 의 뜻을 가지고 있습니다.
위에서 구독을 할 때 메모리가 필요하다고 했었죠?
이 Disposable을 처리를 해야 구독이 끝난 후 메모리에서 해제됩니다.
근데 분명 완료(onCompleted) 혹은 에러(onError) 이벤트가 방출되면 알아서 disposed된다고 배웠었죠?
뭐야! 그런데 왜 또 이렇게 신경써줘야 하냐고~!~!
만약 .dispose 메소드를 사용하지 않는다면?
에러는 아니지만 xcode가 이렇게 혼을 냅니다 ㅠㅠ
사실 우리가 지금까지 알아본 옵저버블은 기본적인 옵저버블입니다.
(이것과 관련된 hot / cold observable이라는 내용도 있지만 다음에 다루겠습니다.)
위의 사진은 예시는 1, 2, 3이라는 원소를 모두 방춮하면 구독이 종료가 되겠죠? 그럼 onCompleted(혹은 onError) 이벤트 방출 후 disposed 될 것입니다. (저 .disposed 메소드를 사용할 필요가 없겠죠. 이 경우에는 스스로 해제가 되니까)
하지만 어떤 버튼을 클릭할 때마다 이벤트를 받는 경우라면 어떨까요?
이러한 경우에 만약 onCompleted 혹은 onError가 발생한다면 우리는 더 이상 클릭 이벤트를 받을 수 없습니다!
(이벤트 방출 후 자동으로 diposed되기 때문에!)
그래서 UI와 관련된 Observable은 완료, 에러 이벤트를 방출하지 않습니다.
즉, 구독이 자동으로 끝나지 않고 사용자가 직접 해제를 해야합니다.
후... 이런 옵저버블도 있기 때문에 .disposed() 메소드를 사용해서 리턴값인 Disposable을 처리해야 하는겁니다!
뭔가 설명이 길었지만,,
Disposable은 구독중인 객체의 메모리 할당을 해제하여 이벤트 구독을 중지하는 역할을 한다!
그리고 구독이 많아지면 각각의 disposable을 관리하는 것은 비효율적이겠죠?
이럴 경우에는 DisposeBag이라는 클래스를 사용에서 한 번에 처리할 수 있습니다.
이런 식으로 사용하면 저 쓰레기통인 disposeBag을 한 번만 DeInit 시키면
그 안에 들어있던 disposable들(예제에서는 3개죠?)을 한 번에 쇽쇽 처리할 수 있습니다!
disposeBag을 가지고 있는 클래스가 DeInit되면 disposeBag도 알아서 DeInit되고 그 disposeBag 안에 있던 Disposable들이 처리되겠죠?
이렇게 간단하게(?) Rx에 대해서 조금이나마 맛을 봤습니다.
사실 Rx의 범위는 너무 넓기 때문에 나눠서 정리하는 것이 훨씬 효율적이라고 생각됩니다!
나머지 내용들(Observable의 연산자, subject와 relay, driver와 signal, hot / cold observable 등... 헉헉)은 다음 시간에 정리하겠습니다!
피드백은 언제나 환영입니다!!!
아래는 RxSwift 사용 예제입니다.
https://github.com/LeeMyungJic/RxSwift_Exsample
'iOS > RxSwift' 카테고리의 다른 글
RxSwift - Driver vs Signal (0) | 2022.07.07 |
---|