Danny의 iOS 컨닝페이퍼
article thumbnail

시작

이전 글에서 [iOS/Swift] MVVM 패턴의 Data Binding에 대해서 알아보자! (Closure, Observable, Combine) 

간단하게 바인딩을 하는 법을 알아봤습니다.

 

이전 글의 방법은 'ViewModel -> View 바인딩'으로 

어디선가 데이터를 받아오면, ViewModel의 데이터들이 View와 결합되어, 즉시 View에 업데이트 되게 만들었고

 

이번에 공부해 볼 것은 'View -> ViewModel 바인딩' 에 대해서 알아보려고 합니다.

말 그대로 이번엔 View(사용자)에서 입력 받은 데이터를 즉시 ViewModel에 결합시키는 방법을 배워봅시다.

 

일단, 들어가기 전에 간단히 로그인 화면을 생각해 봅시다.

 

로그인 화면은 먼저 사용자가 ID와 Password를 입력을 해야 합니다.

만약, 사용자가 입력한 즉시 데이터가 업데이트 된다면, 데이터 관리도 편하고 반응성도 빨라지게 되겠죠?!

지금 우리가 배우려고 하는 건 바로 이겁니다!

 

즉, View에 입력된 데이터를 즉시 ViewModel에 업데이트하는 방법

다시 말해, 'View(사용자)에서 ViewModel로 결합이 되게 만드는 방법을 알아보려 합니다.

 

어떻게 만들 수 있을까요?

이전 글 을 보셨다면 생각보다 간단한데요.

 

새롭게 TextField를 클래스를 재정의해서 문자가 입력될 때마다,

변경된 Text를 ViewModel과 Binding을 시켜주면 됩니다.

 

이와 같은 방식으로 TextView, TableView, Guesture, Button, Switch 등등 내장된 여러 클래스에서도

재정의 하여 사용할 수 있습니다.

 

말로는 어려우니 아래 코드를 보며 간단하게 TextField로 바인딩하는 방법을 알아봅시다.

 

 

TextField 재정의

로그인 화면을 다 만들긴 귀찮으니, Label, TextField, Button을 통해 간단한 예제를 만들어 봤습니다.

 

먼저, Binding을 하기 위해서 TextField를 재정의 해보겠습니다.

 

Binding을 하는 방법은 이전 글 과 거의 비슷합니다.

 

이전 글의 저장속성(value)에서 didSet 사용하는 대신,

addTarget을 통해 Text가 변하게 되면 클로저(listener == 동작)를 통해 동작을 실행해 주는 방식이죠!

class BindTextField: UITextField {
    
    // 동작들을 저장합니다
    private var listener: ((String) -> Void)?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setup() {
        addTarget(self, action: #selector(textDidChanged), for: .editingChanged)
    }
    
    // Text가 변하면 담아준 동작을 실행
    @objc func textDidChanged(_ textField: UITextField) {
        guard let text = textField.text else { return }
        listener?(text)
    }
    
    // 사용하기 간편하게 메서드로 동작을 담아서 사용합시다.
    func bind(_ listener: @escaping (String) -> Void) {
        self.listener = listener
    }
}

 

그리고 간단하게 ViewModel도 만들어주고

class ViewModel {
    
    private var name: String = ""
    
    var nameStr: String {
        return name
    }
    
    func setName(_ text: String) {
        self.name = text
    }
}

 

기본 UITextFiled 대신 재정의한 TextField를 사용하여, bind를 해주면 

View -> ViewModel 형식의 바인딩을 할 수 있게 됩니다!

class ViewController: UIViewController {
    
    let viewModel = ViewModel()
    
    let textLabel = UILabel()
    // binding을 하기 위해 재정의한 TextField를 사용
    let nameTextField = BindTextField()
    let enterButton = UIButton()

    override func viewDidLoad() {
        super.viewDidLoad()
        binding()
    }
    
    private func binding() {
        // 사용자에 의해 입력된 Text를 ViewModel의 name에 바로 업데이트되게 됩니다.
        nameTextField.bind { [weak self] nameStr in
            self?.viewModel.setName(nameStr)
        }
    }
    
    @objc func buttonTapped(_ button: UIButton) {
        textLabel.text = "이름: \(viewModel.nameStr)"
    }
}

 

이렇게 만들어주면, TextField에서 입력된 값이 바로 ViewModel의 name과 결합되게 됩니다.

즉, 사용자가 View에서 입력하는 값을 즉시 ViewModel에 저장이 되겠죠!!!

 

 

마무리

위에도 말했지만, TextField 말고도 내장되어 있는 모든 클래스에서 응용이 가능하여,

바로 업데이트가 되는 반응형 프로그래밍으로 설계를 할 수 있습니다.

 

그리고 만약, 아직 Rx를 안 배우셨다면, Rx와 비슷하게 동작을 구현할 수 있는 좋은 방법이고

Rx를 배우기 전, 대략적으로 어떤 방식으로 RxSwift가 동작하는지 알아볼 수 있는 방법일 것 같아 보이네요.

 

 

 

반응형
profile

Danny의 iOS 컨닝페이퍼

@Danny's iOS

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!