반응형

겁나 오래 살아 남아 있는 iOS 개발자가 RxSwift와 Combine 처음 봤을 때

iOS 개발을 2009년 부터 시작한 고인물 개발자 입니다. 너어어어무 고전 기술? 로만 앱을 만들고 유지보수 해봐서 그런지 RxSwift와 Combine을 처음 봤을 때 솔직히 당황했습니다.

"이게 뭐지? 왜 이렇게 복잡하게 하지?"

혹시 저처럼 느끼신 분들을 위해 정리해봤습니다.


먼저, 둘의 관계

RxSwift

  • 서드파티 라이브러리
  • iOS 8부터 사용 가능
  • 2015년부터 사용됨

Combine

  • Apple 공식 프레임워크
  • iOS 13 이상만 지원
  • 2019년 WWDC에서 발표

결론부터 말하면, 개념은 거의 똑같고 이름만 다릅니다.

RxSwift를 알면 Combine은 쉽고, Combine을 알면 RxSwift도 쉽습니다.


용어 비교표

개념 RxSwift Combine
데이터 발행 Observable Publisher
데이터 구독 Observer Subscriber
구독 해제 dispose() cancel()
메모리 관리 DisposeBag Set<AnyCancellable>
구독 메서드 subscribe sink
값 래퍼 BehaviorRelay @Published

기존 UIKit 방식 (우리가 익숙한 것)

버튼을 누르면 라벨 텍스트가 바뀌는 코드입니다.

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

@objc func buttonTapped() {
    label.text = "눌렸다"
}

직관적이죠? 버튼 눌리면 → 함수 실행 → 라벨 변경

10년간 이렇게 해왔습니다.


RxSwift 방식

let disposeBag = DisposeBag()

button.rx.tap
    .subscribe(onNext: { _ in
        label.text = "눌렸다"
    })
    .disposed(by: disposeBag)

Combine 방식

var cancellables = Set<AnyCancellable>()

button.publisher(for: .touchUpInside)
    .sink { _ in
        label.text = "눌렸다"
    }
    .store(in: &cancellables)

나란히 비교하면 거의 똑같음

보시면 구조가 동일합니다.

단계 RxSwift Combine
1. 이벤트 소스 button.rx.tap button.publisher(for:)
2. 구독 .subscribe(onNext:) .sink { }
3. 메모리 관리 .disposed(by: disposeBag) .store(in: &cancellables)

핵심 개념 3가지 (둘 다 동일)

1. Publisher / Observable (발행자)

데이터를 내보내는 쪽입니다.

"나 값 바뀌면 알려줄게"라고 선언하는 겁니다.

Combine:

@Published var name: String = ""

RxSwift:

let name = BehaviorRelay<String>(value: "")

2. Subscriber / Observer (구독자)

데이터를 받는 쪽입니다.

Combine:

$name
    .sink { newName in
        print("이름 바뀜: \(newName)")
    }

RxSwift:

name
    .subscribe(onNext: { newName in
        print("이름 바뀜: \(newName)")
    })

3. Operator (연산자)

중간에서 데이터를 가공합니다. 검색창 예시로 보겠습니다.

Combine:

$searchText
    .debounce(for: 0.3, scheduler: RunLoop.main)
    .filter { $0.count >= 2 }
    .sink { text in
        self.search(text)
    }
    .store(in: &cancellables)

RxSwift:

searchText
    .debounce(.milliseconds(300), scheduler: MainScheduler.instance)
    .filter { $0.count >= 2 }
    .subscribe(onNext: { text in
        self.search(text)
    })
    .disposed(by: disposeBag)

거의 똑같죠? debounce, filter 같은 연산자 이름도 동일합니다.


메모리 관리 비교 (중요!)

이거 빼먹으면 둘 다 동작 안 합니다.

Combine:

var cancellables = Set<AnyCancellable>()

$name
    .sink { print($0) }
    .store(in: &cancellables)  // 필수!

RxSwift:

let disposeBag = DisposeBag()

name
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)  // 필수!

역할은 같습니다. 뷰컨트롤러가 해제될 때 구독도 같이 정리하는 거예요.


그래서 뭘 써야 하나요?

RxSwift를 써야 할 때:

  • iOS 13 미만 지원해야 할 때
  • 이미 RxSwift로 된 프로젝트 유지보수할 때
  • RxCocoa의 UI 바인딩이 필요할 때

Combine을 써야 할 때:

  • 새 프로젝트 시작할 때
  • iOS 13 이상만 지원해도 될 때
  • SwiftUI 쓸 때 (Combine 기반이라 궁합 좋음)
  • 외부 의존성 줄이고 싶을 때

솔직한 후기

처음엔 "왜 이렇게 복잡하게?" 싶었습니다.

근데 검색창처럼 "입력 → 딜레이 → 필터 → API 호출" 같은 흐름은 확실히 코드가 줄어듭니다.

UIKit으로 같은 걸 만들려면 Timer 쓰고, 플래그 변수 만들고, 취소 로직 넣고... 더 복잡해요.

아직 완벽히 익숙하진 않지만, 하나씩 적용해보는 중입니다.

하나만 익히면 다른 하나는 자동으로 따라옵니다. 용어만 다르니까요.


위 내용은 클로드에게 물어가며 적어 본 내용입니다.

반응형
Posted by onlyTheOne
,
반응형

지난 편에 이어서...  (링크 : https://opendev4u.tistory.com/181 )

최초에 질문 했을때 combine 사용한 예시 코드를 설명해 주었다. 

그래서 다음과 같이 다시 물어보았다.

"그럼 mvvm 구현을 위해 combine을 써야 한다고 말해줘야 하는거 아닌가?" 

라고 물었더니 다음과 같이 피드백을 주었다. 

다음과 같이 피드백을 주었다. 

MVVM 을 구현 한 소스코드 예시는 크게 3가지 방법을 알려주었다. 

Combine 없이 구현 하는 방법 / Combine 이용하는 방법 / RxSwift 이용하는 방법 

그리고 부가 설명을 해주었다. 

과연 이것만 가지고 이해가 될까?? 아직 부족해 보이고... 아하 하기엔 애매한 면이 있어

더 공부 해 볼겸 해서 좀 더 물어보면서 파보기로 했다.

#3 에 이어서...

반응형
Posted by onlyTheOne
,
반응형

나는 아직 MVVM을 제대로 사용해 본적이 없다.

MVVM 을 사용할 만한 서비스 앱을 아직 운영해보거나 개발해 본적이 없다.

개인 스터디로 하기엔 먼가 한계가 있어 보였다. 

그래서 최근 쓰기 시작한 Claude 를 통해 MVVM을 정리해보고자 한다. 

다음과 같이 질문 했다.

"mvvm 에 대해서 설명해줘 나는 도무지 모르겠어 이해가 안되... 이해좀 시켜주었으면 해" 

Claude의 답은 다음과 같았다 .

< 스크린샷 1번 : Claude가 설명해 준 mvvm 에 대한 답변 >

 

MVVM의 핵심은... 내가 잘못 이해 했을 수도 있지만 

- 데이터 바인딩을 통한 자동 업데이트 

이지 않을까 싶다. 

그 이유는 Claude가 설명해 주며 Combine을 활용한 코드를 안내해 주었다.

이 소스코드를 보면서 일부 생략? 누락? 한 듯한 로직이 보여서 눈으로 읽어 컴파일 돌려 보았다. 

눈에 뜨던게 .sink 라는 블록 함수? 와 &cancellables 라는 항목명이 눈에 띄었다.

이건 머지?라고 인터넷에서 검색을 하고 나서 보니.... Combine을 이용한 코드 였던 것이다. 

나는 Combine에 대한 존재는 알고 있었다. mvvm을 좀더 쉽게?구현하는데 RxSwift라는 3rd party 라이브러리가 있고 

이것과 유사한 라이브러리가 Apple에서 제공해준게 Combine 이였기 때문이다. 

그런데 코드가 누락된? 부분이 많아 실제 컴파일 돌리기엔 리스크가 컸다. (사실 컴파일 에러도...)

먼가 이상함을 느껴 다시 Claude에게 질문해 보았다.

"이 코드에 .compactMap하고 sink 함수는 rxswift에 있는거야? 아님 combine에 있는거야" 

답은 다음과 같이 나왔다. 

 

내용을 보면 RxSwift, Combine비교 내용도 있고 어떤 상황이냐에 따라 어떤걸 쓸지도 알려주고 있었다. 

To be continue...

반응형
Posted by onlyTheOne
,