Swift의 Input-Output 패턴
input-output 패턴은 ViewModel에서 사용자의 입력을 받아서 출력을 생성하는 방식으로 주로 Combine 이나 RxSwift를 활용한 비동기 데이터 스트림을 다루는데 사용한다.
Input-Output 패턴
- Input: View 에서 발생하는 이벤트(사용자 입력, 버튼 클릭, 텍스트 입력 등)
- Output: ViewModel에서 처리된 결과 값(네트워크 응답, 가공된 데이터 등)
View는 Input 을 ViewModel에 전달하고, ViewModel은 Output을 View에 전달하는 구조로 데이터의 흐름을 단방향으로 유지할 수 있어 유지보수가 용이하다는 장점을 가지고 있다.
기본적인 Input-Output 패턴 구조
Input-Output 패턴의 구조는 주로 ViewModel 에서 Input 과 Output을 정의해서 사용한다.
import RxSwift
import RxCocoa
protocol ViewModelType {
associatedtype Input
associatedtype Output
func transform(input: Input) -> Output
}
위 처럼 Input 과 Output 을 정의하고, transform(input:) 메서드를 사용하여 변환하는 구조를 만든다.
ViewModel 구현
import RxSwift
import RxCocoa
class LoginViewModel: ViewModelType {
struct Input {
let email: Observerble<String>
let password: Observerble<String>
let loginTap: OBserverble<Void>
}
struct Output {
let isLoginEnabled: Observerble<Bool>
let loginResult: Observerble<Bool>
}
private let disposeBag = DisposeBag()
func transform(input: Input) -> Output {
let isLoginEnabled = Observerble.combineLatest(input.email, input.password)
.map{ !$0.isEmpty && $1.count >= 6 }
let loginResult = input.loginTap
.flatMapLatest {
return Observerble.just(true)
}
return Output(isLoginEnabled: isLoginEnabled, loginResult: loginResult)
}
}
View 에서 ViewModel 을 사용하는 방법
import UIKit
import RxSwift
import RxCocoa
class LoginViewController: UIViewController {
private let viewModel = LoginViewModel()
private let disposeBag = DisposeBag()
private let emailTextField = UITextField()
private let passwordTextField = UITextField()
private let loginButton = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
let input = LoginViewModel.Input(
email: emailTextField.rx.text.orEmpty.asObservable(),
password: passwordTextField.rx.text.orEmpty.asObservable(),
loginTap: loginButton.rx.tap.asObservable()
)
let output = viewModel.transform(input: input)
output.isLoginEnabled
.bind(to: loginButton.rx.isEnabled)
.disposed(by: disposeBag)
output.loginResult
.subscribe(onNext: { isSuccess in
print("로그인 결과: \(isSuccess)")
})
.disposed(by: disposeBag)
}
}
Input-Output 패턴을 사용하는 이유
- 단방향 데이터 흐름 유지
- ViewModel 과 View의 결합도를 낮춰 유지보수 용이
- 테스트하기 쉬운 구조로 변환 가능
- 비동기 이벤트를 명확하게 다룰 수 있음
'TIL(Today I Learned)' 카테고리의 다른 글
| 2025.02.24 Today I Learned (0) | 2025.02.24 |
|---|---|
| 2025.02.14 Today I Learned (0) | 2025.02.14 |
| 2025.01.24 Today I Learned (0) | 2025.01.24 |
| 2025.01.16 Today I Learned (1) | 2025.01.16 |
| 2025.01.13 Today I Learned (0) | 2025.01.13 |