[내일배움캠프 10주차 (03/10)]

yeseul jang·2026년 3월 10일

내일배움캠프

목록 보기
18/32

📘 RxSwift란 무엇인가

  • 비동기 이벤트 스트림을 함수형 방식으로 처리하기 위한 라이브러리
  • 데이터의 변화(이벤트)를 흐름(Stream)으로 보고 처리하는 방식

🔎 이전 코드와 다른 점

button.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)

@objc func didTapButton() {
    print("버튼 눌림")
}
  • 버튼이 눌림 -> 이벤트 발생 -> 함수 호출
  • 이벤트를 직접 연결해야 함
button.rx.tap
    .subscribe(onNext: {
        print("버튼 눌림")
    })
  • 버튼 눌림 -> 스트림 -> 구독(subscribe) -> 실행
  • 변경사항을 뿌리면 관련 사항

🔎 RxSwift가 해결하려는 문제

  • 앱에서 다양한 이벤트의 흐름관리를 간단하게 처리함
  • 모든 걸 이벤트 스트림으로 통일하고 이 스트림을 연결해서 사용

🔎 RxSwift 핵심 개념

  • Observable: 이벤트를 발생시키는 것
  • Observer: 이벤트를 받는 것
  • Subscribe: 연결
  • Observable → Subscribe → Observer

📘 Observable

Observable.just: 값 하나
Observable.of: 여러 값을 직접 넣음
Observable.from: 배열을 풀어서 보냄
Observable.create: 내가 직접 이벤트 생성

// 예시 에러 선언
struct MyError: Error {}

// 구독 해제를 위한 DisposeBag 선언
// 구독을 하고 나선 구독 해제를 반드시 해줘야함
let disposeBag = DisposeBag()


// observable 생성.
// create 클로저 안에 방출할 데이터를 선언
let observable = Observable<String>.create { observe in
    // 정상적인 데이터 방출
    observe.onNext("Apple")
    observe.onNext("Banana")
    observe.onNext("Cake")
    
    // 에러 방출
    observe.onError(MyError())
    
    // Disposables.create 를 리턴해줌으로써 Observable 생성 완료.
    return Disposables.create()
}

// 구독 (subscribe).
// 각 상태에 따라서 스트림이 흘렀을 때 어떤 행동을 취할 것인지 정의
observable.subscribe(onNext: { data in
    print("onNext: \(data)")
}, onError: { error in
    print("onError: \(error)")
}, onCompleted: { 
    print("onCompleted")
}, onDisposed: {
    print("onDisposed")
}).disposed(by: disposeBag)

🔎 Trait란 무엇인가?

  • Trait는 특정한 특징을 가진 Observable의 종류
  • 다양한 상황에 맞추어 Observable을 더 안전하게 쓰기 위해 Trait를 사용함

📍 Trait 종류

  • PrimitiveSequence: Single, Maybe, Completable
  • UI Trait: Driver, Signal

🔎 Single / Maybe / Completable

  • 주로 비동기 작업에서 사용함(네트워크 요청, DB 저장, 파일 작업)

📍 Single

  • 성공하면 값 1개만 보내고 종료하는 Observable
  • 네트워크 요청에서 많이 사용
func fetchUser() -> Single<User> {
    return Single.create { single in
        
        let user = User(name: "yeseul")
        
        single(.success(user))
        
        return Disposables.create()
    }
}
  • single은 이벤트가 딱 두개(success(value),
    failure(error))
  • onSuccess : Observable의 onNext 와 같은 개념.
  • onFailure : Observable의 onError 와 같은 개념.
  • onCompleted 는 존재하지 않음. 하나의 값을 방출하거나, 에러를 방출하면 곧바로 스트림이 종료
fetchUser()
    .subscribe(onSuccess: { user in
        print(user.name)
    })

📍 Maybe

  • 하나의 값을 뱉거나, 값을 뱉지 않고 그냥 complete 되거나, 에러를 방출.
  • 값이 있을수도 없을수도 있음
  • 하나의 값을 방출하거나, 에러를 방출하면 곧바로 스트림이 종료
  • 값을 방출하지 않고 그냥 complete 될 수도 있음

📍 Completable

  • 값을 뱉지 않고 무언가 완료되는 시점만 알고싶을때는 Completable 을 사용합니다.
  • 유의미한 값이 필요없고, 무언가 로딩이 되었다가 완료 시점을 알고싶을 때 사용

🔎 Driver / Signal

  • UI 전용 Trait
  • Driver - 상태 전달, Signal - 순간 이벤트 전달
  • 둘다 공통적으로 error를 방출 안함, 메인 스레드 보장, UI 바인딩 적절

📍 Driver

  • 현재 상태(state)를 표현할 때 사용
  • ex) 현재 라벨 텍스트, 현재 count 값, 현재 영화 목록
  • 지금 화면의 어떤 상태인가
  • 그래서 늦게 본 사람들도 최신상태 볼 수 있음
viewModel.title
    .drive(label.rx.text)
    .disposed(by: disposeBag)

📍 Signal

  • 한 번 발생하고 지나가는 이벤트(event)를 표현할 때 사용
  • ex) 버튼 탭, 화면 전환, 얼럿

📘 Operator

  • Observable에서 흐르는 데이터를 변환 / 필터 / 결합하는 함수
  • Observable 흐름 중간에서 데이터를 가공하는 역할
  • Observable -> Operator -> Operator -> subscribe
  • 간단한 예시
    텍스트 입력 -> 문자열 길이 계산 -> 길이가 5 이상이면 버튼 활성화

📍 merge

  • 여러 Observable의 이벤트를 그대로 섞어서 방출
Observable.merge(button1.rx.tap, button2.rx.tap)

📍 concat

  • Observable을 순서대로 실행, 첫 번째가 끝나야 다음 실행
  • 예시) 캐시 먼저 조회 없으면 서버 요청

📍 combineLatest

  • 여러 Observable 중 하나라도 값이 바뀌면 최신 값들을 묶어서 방출
  • 예시) 아이디 입력, 비밀번호 입력 둘다 묶어서 확인가능

📍 withLatestFrom

  • 특정 Observable이 트리거가 될 때 다른 Observable의 최신 값 가져오기
  • 예시) 버튼 누를 때 -> textField 최신값 가져오기/ 검색버튼 + 검색어

📍 share

  • Observable을 여러 subscriber가 공유
  • 예시) API 호출 1번만 하고 결과 공유

📘 Scheduler

  • Observable 스트림에서 스레드를 지정할 수 있도록 돕는 도구

🔎 Scheduler 종류

📍 MainScheduler

  • 메인 스레드에서 작업을 실행하는 스케줄러입니다.
  • 주로 UI 업데이트와 관련된 작업을 실행할 때 사용
    예: MainScheduler.instance

📍 ConcurrentDispatchQueueScheduler

  • 비동기 작업을 위한 DispatchQueue 기반의 스케줄러
  • 여러 스레드에서 동시 작업을 처리할 수 있음
  • 예: ConcurrentDispatchQueueScheduler(qos: .background)

📍 SerialDispatchQueueScheduler

  • 특정 DispatchQueue에서 직렬 작업을 실행하는 스케줄러
  • 동시성이 필요 없는 작업을 특정 스레드에서 순서대로 처리할 때 유용

🔎 subscribeOn / observeOn

  • subscribOnobserveOn 은 옵저버블이 처리되어야 할 스레드를 지정하는 역할

  • subscribeOn : 스트림의 시작되는 곳의 스레드를 지정

  • observeOn : 다운스트림의 스레드를 지정

📍 subscribeOn

  • Observable이 시작되는 스레드
  • Observable 생성 + upstream 작업을 어디서 할지 결정
Observable.of(1,2,3)
    .subscribe(on: ConcurrentDispatchQueueScheduler(qos: .background))
    .subscribe(onNext: {
        print(Thread.isMainThread)
    })
  • 코드설명: Observable 작업이 background에서 실행

📍 observeOn

  • 이후 operator와 subscribe가 실행될 스레드
  • 결과를 어디서 처리할지 결정
Observable.of(1,2,3)
    .observe(on: MainScheduler.instance)
    .subscribe(onNext: {
        print(Thread.isMainThread)
    })
  • 코드설명: subscribe가 main thread에서 실행

📍 같이 쓰일때

Observable.of(1,2,3)
    .subscribe(on: backgroundScheduler)
    .observe(on: MainScheduler.instance)
    .subscribe(onNext: {
        print(Thread.isMainThread)
    })
  • Observable 작업은 background
  • subscribe 처리는 main
api.fetchMovies()
    .subscribe(on: ConcurrentDispatchQueueScheduler(qos: .background))
    .observe(on: MainScheduler.instance)
    .subscribe(onNext: { movies in
        self.collectionView.reloadData()
    })
  • API 호출은 background
  • UI 업데이트은 main

📘 Subject / Relay

  • Observable이면서 동시에 Observer 역할을 하는 객체
  • 값을 받을 수도 있고 값을 보낼 수도 있음

🔎 Subject

📍 PublishSubject

  • 구독 이후 이벤트만 받음
let subject = PublishSubject<String>()

subject.onNext("A")
subject.onNext("B")

subject.subscribe(onNext: {
    print($0)
})

subject.onNext("C")
// C
  • A,B는 subscribe 이전 이벤트라 구독 이전이라서 안나옴

📍 BehaviorSubject

  • 최신 값을 저장하고 구독 시 전달
let subject = BehaviorSubject(value: "A") // 초기값 A

subject.onNext("B")  // B 등록

subject.subscribe(onNext: {
    print($0) // 등록하는 순간 최신값 뱉음
})

subject.onNext("C")  // C 등록하고 구독자가 있으니 C 뱉음

🔎 Relay

  • error / completed가 없는 Subject
  • 값 전달만 가능하고 스트림 종료 없음

📍 PublishRelay

let relay = PublishRelay<String>()

relay.subscribe(onNext: {
    print($0)
})

relay.accept("Hello")
relay.accept("RxSwift")
// Hello
// RxSwift
  • onNext가 없고 accept사용

📍 BehaviorRelay

let relay = BehaviorRelay(value: 0)

relay.accept(1)
relay.accept(2)

relay.subscribe(onNext: {
    print($0)
})
// 2
  • 현재값 저장
  • 뷰모델 상태관리에 사용됨
profile
iOS 개발

0개의 댓글