cchanmi
[iOS] RxSwift 정리 본문
최근 RxSwift + ReactorKit 프로젝트를 진행했었는데요.
프로젝트 후반에 접어들면서 RxSwift에 대해 제대로 이해하고 썼는가에 대한 의문이 들어서 정리하는 포스팅을 작성하게 되었습니다.
RxSwift란?
Reactive Extension Swift의 약자로 swift로 반응형 프로그래밍을 구현할 수 있도록 도와주는 라이브러리입니다.
반응형 프로그래밍은 데이터의 스트림이나 변경 사항에 반응하여 실행되는 프로그래밍 패러다임입니다.
RxSwift 사용하는 이유
그렇다면 러닝커브가 높다고 소문이 자자한 RxSwift를 그렇게 많은 사람들이 사용하는 이유가 뭘까요?
제가 직접 사용해 보고 느낀 장단점에 대해서 정리해 보자면
장점
- 기존 @objc, delegate, closure, notification 등 여러 비동기 처리 코드를 사용하였을 때, 비동기 코드들이 분산되어 있어서 작업 흐름을 알기 어려웠지만, RxSwift를 사용하면 비동기 코드를 하나로 통일하여 집중화할 수 있습니다.
- 위의 의견을 바탕으로 비동기적으로 발생하는 결과값을 completion closure를 전달하여 사용하지 않고, return 값으로 전달할 수 있게 되며, 이는 비동기로 동작하는 코드를 보다 더 동기적으로 작성할 수 있게 되며, 코드의 직관성을 높일 수 있게 됩니다.
- thread 처리가 간단해집니다.
- 이건 개인적으로 느꼈던 장점인데... 이전 프로젝트에서 UIKit+Combine을 사용했었는데요. 개인적으로 MVVM 구조를 유지하면서 데이터를 바인딩하는 것이 어려웠고, UIControl에 관련된 컴포넌트 이벤트 처리들을 직접 구현해 주어야 했어서 많은 불편함을 겪었습니다. 그래서 그런지 RxSwift의 rx.tap을 사용해서 대부분의 컴포넌트들에 이벤트 처리가 연동되었다는 점과 바인딩 또한 쉽게 할 수 있었다는 점에 신세계를 겪었었네요... (이전에 불편함을 겪었어서 그런지 더...!)
단점
- 러닝커브가 높다. 하지만 그만큼의 이점도 있다고 생각하기 때문에, 그만한 러닝커브가 있는 게 당연한 것이 아닐까...!라고 생각합니다.
- 클로저 사용으로인해 순환 참조 사이클 또한 메모리 누수가 발생할 수 있기 때문에 주의해야 합니다.
또 많은 분들이 디버깅이 어렵다는 단점을 많이 말씀해 주셨었는데, 개인적으로 여러 비동기 처리 코드를 작성하였을 때 분산된 코드들로인해 데이터의 흐름을 쉽게 파악하기가 어려웠어서 오히려 데이터 흐름을 통일시킨 RxSwift를 사용했을 때 디버깅이 훨씬 간편함을 느낀 경험이 있어서 공감이 되지는 않았습니다. 추가로 디버깅을 위한 operator도 존재하구요!
Observable, Subscriber
반응형 프로그래밍이 구현되려면 두 가지가 충족되어야 합니다.
1) 데이터 및 이벤트를 방출할 스트림
2) 해당 스트림을 관찰하고 있다가, 해당 스트림에 어떠한 변화가 생겼을 경우, 구독하여 어떠한 이벤트 처리를 해 주는 구독자
이 두 가지를 각각 Observable, Subscriber라고 부릅니다.
Observable
Observable은 데이터 또는 이벤트 스트림을 방출합니다.
쉽게 말해서 Observable을 Subscriber가 구독해서 그에 맞는 이벤트를 처리한다고 이해하면 좋을 것 같습니다.
Observable은 3가지의 이벤트가 있습니다.
1) next : 이벤트를 받아서 원하는 형태로 처리하는 역할을 합니다.
2) error : 이벤트를 방출하다가 에러가 발생한 경우 error 이벤트를 방출하고 스트림을 종료시킵니다.
3) completed : 성공적으로 next 이벤트가 완료되었을 때, complete 이벤트가 발생합니다. complete 이벤트가 발생 후, 스트림이 종료됩니다.
Subscriber
쉽게 말해서 구독자라고 생각하면 좋을 것 같습니다.
Observable을 계속해서 관찰하고 있다가 어떠한 변화가 발생했을 때, 구독하여 이벤트 처리를 해 주는 역할을 합니다.
둘의 관계를 예제 코드를 통해 알아보면 이렇습니다.
let disposeBag = DisposeBag()
let observable = Observable.just("Hello, RxSwift!")
observable.subscribe { event in
switch event {
case .next(let value):
print("Next:", value)
case .completed:
print("Completed")
case .error(let error):
print("Error:", error)
}
}
.disposed(by: disposeBag)
// Next: Hello, RxSwift!
// Completed
Disposeable
dispoesBag은 메모리 관리를 도와주는 도구입니다.
subscribe가 호출되고 난 이후 disposeable 값이 return 되는 것을 볼 수 있습니다.
Observable에 대한 구독이 일어나고, disposeable이 return 되면서 자동으로 스트림이 종료되는 흐름인 것을 알 수 있는데요.
disposeBag을 사용하여서 구독의 수명을 특정 뷰 컨트롤러나 객체의 수명 주기와 일치시키는 목적으로 사용됩니다.
유저가 홈 화면에 진입 중이라고 가정했을 때, 홈 화면을 벗어나기 전까지는 스트림이 살아 있어야 하기 때문에 구독의 스트림과 뷰의 생명주기를 일치시킨다고 이해하면 좋을 것 같습니다.
'iOS' 카테고리의 다른 글
[RxSwift] RxSwift의 메모리 누수에 대해서 (1) | 2024.09.08 |
---|---|
[iOS] UIKit+Combine 환경에서 CollectionView Cell 바인딩 문제 해결 (1) | 2024.09.07 |
[iOS] CollectionView Cell 재사용에 따른 중복 binding 이슈 해결 (0) | 2024.08.31 |
[iOS] TextView Responder 권한이 남아 있어 Keyboard 감지 Notification이 중복 호출 되는 이슈 해결 (0) | 2024.08.04 |
[iOS] 토큰 만료 플로우 이슈 해결 (0) | 2024.06.14 |