[Swift] ReactorKit 첫걸음: 간단한 카운터 앱 만들기

작성일 :

[Swift] ReactorKit 첫걸음: 간단한 카운터 앱 만들기

ReactorKit은 iOS 애플리케이션의 반응형 프로그래밍을 위한 아키텍처 라이브러리로, React 패턴을 기반으로 합니다. 이 튜토리얼에서는 ReactorKit을 사용하여 간단한 카운터 앱을 만드는 방법을 단계별로 설명하겠습니다. 이 과정을 통해 ReactorKit의 기본 개념과 주요 구성 요소를 익히게 될 것입니다.

1. ReactorKit 소개

ReactorKit은 React 패턴을 적용한 아키텍처로, 애플리케이션 상태 관리와 뷰의 로직을 깔끔하게 분리하는 데 중점을 둡니다. 주요 구성 요소는 다음과 같습니다.

  • Reactor: 애플리케이션의 상태와 로직을 관리합니다.
  • View: 사용자 인터페이스를 담당하며, Reactor의 상태 변화를 구독합니다.
  • Action: 사용자가 발생시키는 이벤트들을 정의합니다.
  • Mutation: Action이 발생했을 때 상태를 어떻게 변경할 것인지 정의합니다.
  • State: 앱의 현재 상태를 나타냅니다.

이제 이 개념들을 실제 코드에서 어떻게 사용하는지 살펴보겠습니다.

2. 프로젝트 설정

먼저, Xcode에서 새로운 프로젝트를 생성하고, ReactorKitRxSwift, RxCocoaCocoaPodsSwift Package Manager를 이용해 설치합니다. Podfile에 다음 내용을 추가한 뒤 pod install을 실행합니다:

ruby
pod 'ReactorKit'
pod 'RxSwift'
pod 'RxCocoa'

3. 기본 구조 설정

Reactor 생성

Reactor는 앱의 상태와 로직을 관리하는 역할을 합니다. 우리는 카운터 값의 증가와 감소를 처리할 것이므로, 다음과 같이 CounterReactor를 정의합니다.

swift
import ReactorKit
import RxSwift

class CounterReactor: Reactor {
    // Action: 사용자 이벤트 정의
    enum Action {
        case increase
        case decrease
    }

    // Mutation: 상태 변화를 정의
    enum Mutation {
        case increaseValue
        case decreaseValue
    }

    // State: 앱의 상태 정의
    struct State {
        var value: Int
    }

    // 초기 상태 설정
    let initialState: State = State(value: 0)

    // Action을 받아서 Mutation으로 변환
    func mutate(action: Action) -> Observable<Mutation> {
        switch action {
        case .increase:
            return Observable.just(Mutation.increaseValue)
        case .decrease:
            return Observable.just(Mutation.decreaseValue)
        }
    }

    // Mutation을 받아서 State로 변환
    func reduce(state: State, mutation: Mutation) -> State {
        var newState = state
        switch mutation {
        case .increaseValue:
            newState.value += 1
        case .decreaseValue:
            newState.value -= 1
        }
        return newState
    }
}

View 설정

이제 ViewController를 설정하여 인터페이스와 Reactor의 상태를 연결합니다.

swift
import UIKit
import ReactorKit
import RxSwift
import RxCocoa

class CounterViewController: UIViewController, View {
    var disposeBag = DisposeBag()
    let increaseButton = UIButton()
    let decreaseButton = UIButton()
    let valueLabel = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(increaseButton)
        self.view.addSubview(decreaseButton)
        self.view.addSubview(valueLabel)
        self.reactor = CounterReactor()
    }

    func bind(reactor: CounterReactor) {
        // Action: 버튼 클릭 시 액션 발생
        increaseButton.rx.tap
            .map { Reactor.Action.increase }
            .bind(to: reactor.action)
            .disposed(by: disposeBag)

        decreaseButton.rx.tap
            .map { Reactor.Action.decrease }
            .bind(to: reactor.action)
            .disposed(by: disposeBag)

        // State: 상태 변화 시 UI 업데이트
        reactor.state.map { $0.value }
            .distinctUntilChanged()
            .map { "\($0)" }
            .bind(to: valueLabel.rx.text)
            .disposed(by: disposeBag)
    }
}

4. UI 구성

Storyboard 또는 코드로 버튼과 레이블을 추가하여 레이아웃을 구성합니다. 이 글에서는 코드로 레이아웃을 구성하는 방법을 보여드리겠습니다.

swift
override func viewDidLoad() {
    super.viewDidLoad()
    self.setupView()
    self.reactor = CounterReactor()
}

func setupView() {
    // 버튼 및 레이블 속성 설정
    increaseButton.setTitle("+", for: .normal)
    increaseButton.setTitleColor(.blue, for: .normal)
    decreaseButton.setTitle("-", for: .normal)
    decreaseButton.setTitleColor(.red, for: .normal)
    valueLabel.text = "0"
    valueLabel.textAlignment = .center
    
    // 레이아웃 설정
    let stackView = UIStackView(arrangedSubviews: [decreaseButton, valueLabel, increaseButton])
    stackView.axis = .horizontal
    stackView.distribution = .fillEqually
    self.view.addSubview(stackView)
    
    stackView.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        stackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
        stackView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
        stackView.widthAnchor.constraint(equalToConstant: 200)
    ])
}

5. 최종 확인

이제 앱을 실행하여 버튼을 클릭할 때마다 카운터 값이 증가하고 감소하는지 확인해 볼 수 있습니다. 정상적으로 작동한다면, 성공적으로 ReactorKit을 이용하여 간단한 카운터 앱을 만든 것입니다.

결론

이번 튜토리얼에서는 ReactorKit의 기본 개념과 구성 요소를 살펴보고, 이를 활용하여 간단한 카운터 앱을 만들어 보았습니다. ReactorKit을 사용하면 상태 관리와 뷰 로직을 깔끔하게 분리할 수 있어 유지 보수와 확장이 용이합니다. 이 글을 통해 ReactorKit의 기초를 이해하고, 더 복잡한 애플리케이션에도 적용할 수 있는 준비가 되었기를 바랍니다.