[iOS] MVVM 패턴? 어떤 장점이 있을까!

12656 단어 MVCMVVMiOSMVC

📒 본론에 앞서 ...

작년에 it동아리 활동을 시작하면서 동아리 내 rxswift 스터디에 들어갔습니다.
그 당시에는 mvc도 제대로 몰랐는데, 단지 rxswift가 취업 우대사항에 포함된다는 소리만 듣고
공부를 시작했습니다. (무식하면 용감하다는 말은 딱 이럴 때 사용하는 말 ..)

이 책으로 함께 스터디를 했었고 스터디를 기록했던 깃허브 주소입니다.

사실 왜 rxswift를 쓰는지 MVVM 은 무엇인지 왜 사용하는지 전혀 이해를 하지 못하고
무작정 공부를 시작했던 터라 요즘 반성을 많이 하고 있습니다 ㅠ_ㅠ

그래서 오늘은 MVVM이 무엇이고 어떤 장점이 있는 구조인지 공부해보고 글을 남겨보겠습니다.



MVC 패턴?

Model / View / Controller로 나누는 패턴입니다.
iOS 에서는 ViewController가 있는데, 규모가 큰 프로젝트에서는 이 VC가 점점 커지고 무거워지면서
Massive ViewController 라는 별명을 가지고 있기도한 패턴입니다.

그래서 우리는 VC의 책임을 덜어줄 다른 패턴을 찾아야 할 필요성이 생겼답니다 !



MVVM 패턴 ?

MVVM 패턴은 Model / View / ViewModel로 이루어져있는 패턴입니다.

MVVM 패턴

  1. 사용자가 화면에서 Action을 취하면 Command Pattern으로 View → ViewModel로 전달됩니다.
  2. ViewModel 이 Model에게 data를 요청합니다.
  3. Model은 요청받은 data를 통해 update된 data를 ViewModel로 전달합니다.
  4. ViewModel은 응답받은 데이터를 가공해서 저장합니다.
  5. View는 ViewModel과의 Data Binding을 통해서 자동으로 갱신됩니다.

여기서 Command Pattern 이란 ?

Command = 명령어
실행될 기능을 추상화, 캡슐화하여 한 클래스에서 여러 기능을 실행할 수 있도록 하는 패턴입니다.

여기서 Data Binding 이란 ?

view와 로직이 분리되어 있어도 한 쪽이 바뀌면 다른 쪽도 업데이트가 이루어 지는 것입니다.

iOS 에서 Data Binding을 하는 방법에는 이런 것들이 있습니다.

  • KVO
  • Delegation
  • Functional Reactive Programming
  • Property Observer

이런 방법들에 대해서는 다른 글에서 다뤄보도록 하겠습니다 :)



간단한 예제 살펴보기

두 개의 텍스트 필드에 사람의 이름과 나이를 적으면 그 아래 label에 표시되는 예제입니다

Model

struct Person {
    var name: String
    var age: Int
}

이렇게 Person 모델을 만들어줍니다.

View Model

struct PersonViewModel {
    typealias Listener = (Person) -> Void
    var listener: Listener?
    
    var person: Person {
        didSet {
            listener?(person)
        }
    }
    ...
    mutating func bind(listener: Listener?) {
        self.listener = listener
    }
}

그리고 UITextField를 상속받는 BindingTextField 클래스를 생성해줍니다.

class BindingTextField: UITextField {
    var textChanged: (String) -> Void = { _ in }
    
    func bind(callBack: @escaping (String) -> Void) {
        textChanged = callBack
        addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)
    }
    
    @objc func textFieldDidChange() {
        guard let text = text else { return }
        textChanged(text)
    }
}

View

override func viewDidLoad() {
    ...
    personViewModel.bind { [weak self] person in
        self?.yearLabel.text = person.name + " " + "\(person.age)세"
    }
    
    
    @IBOutlet weak var nameTextField: BindingTextField! {
    didSet {
        nameTextField.bind { [weak self] name in
            self?.personViewModel.person.name = name
            }
        } 
    }
    
    @IBOutlet weak var ageTextField: BindingTextField! {
    	didSet {
            ageTextField.bind { [weak self] ageText in
            guard let age = Int(ageText) else { return }
            self?.personViewModel.person.age = age
            }
        }
    }
}

이런식으로 구현을 하게되면 View와 ViewModel이 양방향으로 바인딩이 되어있기 때문에
한 쪽에 변화가 생기면 다른 한 쪽도 자동으로 업데이트 되게 됩니다.



🤔 장점과 단점

장점

  1. 유지보수에 좋다.
  2. 자동화된 테스팅에 적합한 모델이다 ( View Model과 View 간의 의존성이 없기 때문에 )
  3. 새로운 개발자라도 빠르게 적응이 가능하고 개발이 가능한 수준의 난이도와 복잡성

단점

  1. 단순한 프로젝트를 개발하기에는 MVC에 비해서는 시간이 오래걸린다.

위처럼 간단한 예제도 꽤나 긴 코드를 작성해야함을 확인할 수 있습니다.
그래서 저도 처음에는 이 간단한 걸 이렇게 긴 코드로 작성을 해야하는데 이게 왜 좋다는거지? 이런 의문이 들었습니다.
그리고 사실 간단한 프로젝트 수준, 유지보수가 굳이 필요하지 않은 프로젝트라면 MVC는 굉장히 좋은 패턴이라는 생각이 듭니다.

하지만 회사에서 사용하는 모든 코드들은 이후에 새로운 기능이 추가될 확률이 굉장히 높고,
유지보수 및 테스트가 용이해야하기 때문에 많은 회사들이 MVVM 패턴을 채택하고 있는 것 같습니다 :)

그렇기 때문에 MVC가 어느정도 익숙해졌고, 새로운 패턴을 적용해서 개발을 해보고싶다! 하시면
MVVM은 좋은 선택지가 될 것 같네요 ~ ㅎㅎ



저도 이번에 스터디를 하면서 MVVM + Rxswift를 사용해 작은 프로젝트를 시작했습니다.
이 부분도 나중에 글로 작성하게 되면 아래에 링크를 남겨두겠습니다 :)

읽어주셔서 감사합니다 !




참고 링크

마기님 블로그
MVVM 디자인패턴

좋은 웹페이지 즐겨찾기