
RxSwift 네이놈. 널 정복하고 말테야.
비동기 이벤트 처리 라이브러리
시간에 따라 바뀌는 값을 깔끔하게 처리할 수 있도록 도와주는 도구
앱을 만들다 보면
버튼을 눌렀을 때 숫자가 오르는 걸 만들어야 하거나
서버에서 데이터를 받아서 화면에 보여줘야 할 때가 생기거나
유저가 텍스트필드에 텍스트를 입력할 때마다 자동 검색이 되어야 할 때가 있을 수 있는데
이런 이벤트들은 시간에 따라 발생하고 인풋에 따른 원하는 행동을 해야 함
이걸 예쁘고 한눈에 보이게 도와주는 게 RxSwift 인데
일반적인 코드에서는
var count = 0
@IBAction func buttonTapped() {
count += 1
label.text = "\(count)"
}
요로코롬 버튼을 눌렀을 때 숫자가 올라가고 라벨이 바뀌게 되는 코드인데
이 정도는 뭐 지금 딱 봤을 땐 깔끔해 보일 수 있지만
만약에 버튼도 여러 개에 여러 뷰도 바꿔야 하고 서버 응답도 받아야 한다면
콜백 지옥에 상태는 꼬일대로 꼬이고 버그가 난무하는 현상이 생길 수도 있음
RxSwift를 사용하면
button.rx.tap
.scan(0) { count, _ in count + 1 }
.map { "숫자: \($0)" }
.bind(to: label.rx.text)
.disposed(by: disposeBag)
버튼이 눌릴 때마다 → 숫자를 하나씩 더하고 → 문자열로 바꿔서 → 라벨에 표시하는 이벤트 흐름을 한 줄로 표현할 수가 있음
계속해서 값을 만들어내는 공장? 느낌이라고 생각하면 됨
데이터를 시간 흐름에 따라 계속 내보내는 애
Observable은 이벤트나 데이터를 흘려보내는 통로 같은 것 !
Observable이라는 친구의 개념을 처음 배울 때 데이터가 흐르는 통로? 라는 공통점 때문인지 시스템 버스가 생각 났는데 덕분에 이해하기 쉬웠던 거 같음
위에 언급했던 예를 가져와보면
버튼을 누를 때마다 눌림 이벤트 발생
서버에서 데이터가 오면 응답 이벤트 발생
타이머가 1초마다 숫자 방출
시간에 따라 일어나는 변화(이벤트)를 계속해서 방출해주는 역할
let stream = Observable.of(1, 2, 3)
이렇게 만들면 1 → 2 → 3 이라는 값이 차례로 나오게 됨
공장에서 나온 데이터를 받는 소비자
Observable이 보내는 값을 구독해서 반응하는 애
Observable이 계속 물건(데이터)을 만들면
Observer는 그걸 구독해서 받아오고 처리하게 됨
Observable.of("🐶", "🐱", "🐰")
.subscribe(onNext: { animal in
print("동물 받음: \(animal)")
})
저렇게 짜게 됐을 때 구독자가 동물이 올 때마다 콘솔에 찍게 됨
중간에서 데이터를 가공하거나 필터링하는 거
Observable에서 나오는 값을 수정||변경해주는 애들
Observable이 데이터를 흘려보낼 때 당연히 중간에서 가공/필터링/변환할 수 있을텐데 이걸 도와주는 친구
Observable.of(1, 2, 3, 4)
.map { $0 * 2 }
.filter { $0 > 4 }
.subscribe(onNext: { print($0) }) // 6, 8 출력
.map { $0 * 2 } → 값을 2배로 바꿈
.filter { $0 > 4 } → 4보다 큰 값만 통과
이렇게 Operator는 중간에서 일하는? 역할
구독을 정리하는 휴지통
메모리 누수를 막기 위해서 구독을 해제할 때 사용
Observer가 Observable을 구독하면 구독된 상태로 계속 살아있게 됨
뷰가 사라졌는데도 계속 구독하고 있으면 뷰 컨트롤러도 메모리에서 안 사라지게 될 거고 그렇게 되면 메모리 누수가 될 것임 점점 쌓이다 보면 앱이 터질수도..
그래서 DisposeBag이라는 휴지통에 구독들을 담아두고
화면이 사라질 때 한꺼번에 정리하게 됨 (휴지통 비우는 느낌이라 생각하면 될 듯)
let disposeBag = DisposeBag()
Observable.of("🤓", "🥸")
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
이러면 뷰가 없어질 때 자동으로 정리되게 될 것임
Observable → Operator → Observer
(이벤트 발생) → (변경/가공) → (값 받기)
버튼 누를 때마다 라벨 숫자 증가하는 걸 만들어 봄
button.rx.tap
.scan(0) { count, _ in count + 1 }
.map { "현재 숫자: \($0)" }
.bind(to: label.rx.text)
.disposed(by: disposeBag)
.rx.tap → 버튼 눌림 이벤트를 스트림으로 만들어줌 (Observable)
.scan(0) → 누적 숫자 카운트 (Operator)
.map → 문자열로 변환 (Operator)
.bind(to:) → 라벨에 바로 바인딩 (Observer)
.disposed(by:) → 메모리 정리 (disposeBag)
이렇게 한 줄씩 이벤트를 이어서 쓰는 걸 체이닝 이라고 하는데
이게 RxSwift 장점이랑 연결 됨
모든 상황에서 Observable 하나로 처리하면 가능은 할 수 있겠지만 복잡해지고 위험할 수 있음 상황에 따라서 공장에서 적절하게 기능을 제공하려면 Observable 안에서도 종류로 나뉘어야 함
뉴스레터 같은 거 구독하면 뉴스 뜰 때마다 계속 메일에 알림이 오도록 하는데 그런 거? 무제한으로 계속 값을 보낼 수 있음
마침 오늘 옷을 샀기 때문에 택배 도착 하는 걸로 이해해보면 택배가 도착했는지 도착하지 않았는지, 그러니까 하나의 결과 (성공 or 실패)만 알려줌 !
Completable 쓰고 보니까 이렇게만 예를 들면 Completable랑 좀 헷갈릴 거 같은데
택배가 도착했는지 여부만 중요하고 안에 뭔지는 관심 없을 땐 Completable에 가깝겠지만
도착했는데 안에 뭐가 들었는지도 알려준다면.. Single의 예시가 됨.
예를 들어 티셔츠가 안에 들어있다는 걸 알고 있다면 Single 임
Single<String>.just("티셔츠 도착!")
이런 식으로.
파일을 저장할 때 저장 완료 했는지 or 실패했는지 알려주는 거 생각하면 편할 듯
→ 값은 없고 됐는지만 중요할 때
택배함 열었는데 도착한 택배가 있거나 없을 수도 있음
이름 그대로 자동차에 비유하자면 안전 운전??
에러 안 나고 항상 메인(UI)에서 동작해서 걱정 없음!
내가 직접 값을 넣을 수 있는 통로라고 생각.. 솔직히 이해하는 건 이게 제일 어려웠음 너무 추상적이라 해야하나. 그래서 이건 코드로 직관적이게 비교해보고 싶음
Observable은 값이 흘러나오는 걸 관찰만 할 수 있고 값을 주입하는 건 불가능함
let tapObservable = button.rx.tap // 버튼 눌렀을 때 이벤트
근데 Relay 얘는
let count = BehaviorRelay<Int>(value: 0)
count.accept(10) // <<<<<<<- 여기
이렇게 값을 넣을 수 있음
Subject는 Observable이면서 동시에 Observer임
Umm.... 솔직히 저 말을 딱 보기만 했을 땐 뭔지 이해하기 어려운데
Observable은 값을 흘리는 쪽이고 Observer은 값을 받는 쪽인데
Subject는 둘 다 가능한 친구인 셈임
Observable처럼 값을 다른 애한테 전달도 할 수 있고
Observer처럼 다른 Observable에게서 값을 받기도 할 수 있는 것
중계자? 라고 생각하면 될 듯

직접 값을 넣을 수 있는 스트림인 셈
항상 마지막에 emit된 값을 기억하고 있다가 새로운 구독자가 생기면 기억한 값을 전달함
let subject = BehaviorSubject(value: 10)
subject.onNext(20) // 20
초기값 있고 (BehaviorSubject는 만들자마자 기본값을 넣어줘야 함. 아무도 구독하지 않아도 일단 기억되게 됨) 가장 최근 값 1개를 기억하고, 새로운 구독자에게 전달
let subject = PublishSubject<Int>() subject.onNext(20)
초기값 없고, 생기는 값만 전달
Observable의 발행 시점이 중요한 상황에서 필요
Cold Observable
구독하는 순간부터 데이터를 보내주기 시작함
구독자가 생겨야 시작
구독한 시점부터 데이터를 받을 수 있음
유튜브 영상처럼 언제 틀어도 처음부터 시작
Observable.of(1, 2, 3)
.subscribe(onNext: { print($0) })
구독하게 되면 1, 2, 3 순서대로 방출
Hot Observable
이벤트가 흘러가고 있으니까 들어오면 그때부터 쭉. 데이터가 구독 여부랑 관계없이 계속 발생
구독 전에도 값이 발생할 수 있고
구독한 시점 이후의 값만 받을 수 있음
생방송 처럼 켜는 순간부터
let subject = PublishSubject<String>()
subject.onNext("🐶") // 이건 구독자 없어도 방출
subject.subscribe(onNext: { print($0) })
subject.onNext("🐱") // 이건 구독자에게 전달
멍멍이는 아무도 못 보고 냥냥이부터 구독자가 볼 수 있음
둘 다 이벤트를 흘려주는 스트림이지만
언제부터 데이터를 보내느냐가 다른 것.
정리가 정말 잘되어있네요 👍