공부하면서 정리한 글이기 때문에 잘못된 내용이 들어가 있을 수 있습니다! 틀린점/이상한 점들이 있다면 피드백 부탁드립니다! 😊
이 글을 읽기 전 MVC 디자인 패턴에 관한 이전 글, MVVM의 탄생 배경에 대한 EEYatHo님의 글을 읽어보시길 추천드립니다!

MVVM 디자인 패턴

위키백과 - MVVM

MVVM은 그래픽 사용자 인터페이스(뷰)의 개발을 비즈니스 로직 또는 백-엔드 로직(모델)로부터 분리시켜서 뷰가 어느 특정한 모델 플랫폼에 종속되지 않도록 해주는 패턴이다. - 위키백과
패턴을 쓰고자 하는 목적은 MVC디자인 패턴과 크게 다르지 않다. (관심사의 분리를 통해 어떤 이점을 얻어내고자 하고 있음)

 

MVVM 패턴의 구성요소는 아래와 같다. - Model, View, ViewModel

모델(Model)

  • 데이터, 네트워크 로직, 비즈니스 로직등을 담으며 데이터를 캡슐화하는 역할을 맡고 있다.

  • View, ViewModel에 대한 신경은 쓰지 않는다. 데이터를 어떻게 가지고 있을지만 걱정하며, 데이터가 어떻게 보여질 것인지에 대해서는 고려하지 않는다.

    → MVC의 Model과 크게 다르지 않다.

뷰(View)

  • 사용자가 화면에서 보는 것들에 대한 구조, 배치, 그리고 외관에 해당하는 내용을 다룬다.

  • Model을 직접 알고 있어서는 안된다.

    → 위의 두가지는 MVC에서의 View 역할과 비슷하다.

  • ViewViewModel로부터 데이터를 가져와서 표현한다.

  • 사용자와 View의 상호 작용을 수신하고 이에 대한 처리를 ViewModel에 부탁한다.

    → 데이터를 보여주고, 사용자와의 상호작용 처리를 다른 객체에게 넘긴다는 점에서 이 부분도 MVC의 View와 비슷해보인다. 하지만 MVC, MVP와는 다르게 MVVM의 View는 보이는 부분에 대한 설정을 스스로 직접 한다.

뷰모델(ViewModel)

  • View로부터 전달받는 요청을 처리할 로직을 담고 있으며 Model에 변화가 생기면 View에 notification을 보낸다. (데이터의 변화를 View가 알아챌 수 있도록 한다고 생각하면 된다)

  • ViewModelViewModel 사이의 중개자 역할을 하며 Presentation Logic을 처리하는 역할을 한다.

    • 중간 다리의 역할을 한다는 점에서 MVC의 Controller와 유사하다고 볼 수도 있다.

    여기서 말하는 Presentation Logic이란?

    • 일반적으로 ViewModelModel 클래스의 메서드를 호출하여 Model과 상호 작용한다. 그런 다음 ViewModelModel의 데이터를 가져오고, View가 쉽게 사용할 수 있는 형태로 가공하여 제공한다.

      ex) View가 데이터를 더 쉽게 처리할 수 있도록(보여줄 수 있도록) 데이터 형식을 다시 지정 (formatting)

 

동작 흐름은 아래와 같다.

  1. View에 들어온 Event를 View Model에게 알려주면 View Model은 Model을 업데이트 시킨다.
  2. Model이 변화하면 이는 View Model에 알려지고, View Model과 바인딩되어있는 View가 업데이트 된다.

 

MVC와의 차이점

  1. MVC: 기본적으로 ViewModel은 다른 구성요소들을 알지 못하며, ControllerViewModel을 모두 알고있는 형태로 구현되어야 했다. (여기서 '기본적'이라고 말한 이유는 꼭 그래야 하는 것은 아니기 때문이다. - 전통적 MVC에서는 ModelView를 알고 있도록 구현되기도 했었음)

    → MVVM: ViewViewModel을 알고 있으며, 소유한다. 그리고 ViewModelModel만을 알고 있도록 구현된다. Model은 다른 구성요소들을 알지 못하도록 만들어져야 한다. (Model만이 MVC와 크게 달라지지 않았다)

  2. MVC: View가 데이터를 보여주는 방식은 크게 두 가지로 나뉘었었다.

    • ModelView를 Observer로 등록하여 데이터를 설정하는 방식 (ModelView를 알고 있는 형태, 전통적 방식, apple이 문제를 제기했던 방식)
    • ViewControllerModel의 변경을 알아차리고 직접 View에 데이터를 설정해주는 방식(apple's MVC)

    → MVVM: ViewViewModel과의 데이터 바인딩을 통해 스스로 데이터를 보여준다. (데이터를 View에 보이게 하기 위한 설정 책임을 View 스스로가 가진다)

  3. MVC(iOS): 사용자 상호작용에 대해 ViewController에게 처리를 부탁하는 것은 Delegate Pattern, Target-Action등을 썼었다.

    → MVVM: ViewViewModel을 알고 있으므로 필요할 때 ViewModel의 메서드를 호출하는 방식으로 구현이 가능하다.(물론 꼭 이렇게 구현해야 하는 것은 아니다.)

 

다시한번 정리...

Apple의 MVC에서는 ViewControllerView에 대한 설정 뿐만 아니라 life cycle관리까지 하는 등 View와 밀접한 관계를 지니고 있었다. 하지만 MVVM에서의 ViewModel은 View를 알지 못하며 View를 설정하는 코드가 전혀 안들어간다.

(데이터 변경에 대해 뷰를 업데이트하는 것은 온전히 뷰의 책임이 되었다)

 

아래는 Heechan님의 블로그 글 내용 중 일부이다.

  • UIKit에서는 한 화면의 구성단위가 ViewController이지만, SwiftUI에서는 한 화면의 구성단위가 View이다. (View가 보여지는 화면을 주도한다)

  • MVC에서는 유저 상호작용이 일어났음을 View -> Controller로 알리고 그에 따라 어떤 행동을 할지는 모두 Controller가 정했다면, MVVM의 ViewModel은 로직만 가지고 있고, 어떤 행동을 할지는 View가 정한다.

  • 데이터가 변경되었음을 알리는 방향은 Model -> Controller, ViewModel로 동일하다. 하지만 MVC에서는 그 사실에 따라 View를 어떻게 다시 그릴지 Controller가 전한 반면, MVVM에서 ViewModel은 바로 View에게 그 소식을 전달하는 역할을 하고 View가 알아서 데이터를 받아와 알아서 다시 그린다.

     

아래와 같은 관점에서 MVC와 MVVM을 비교하는 분들도 계신다.

  • 'UIKit - MVC' 구조는 event driven 방식인데, 'SwiftUI - MVVM' 구조는 data driven 방식이다!

    • UIKit에서는 이벤트에 따라 특정 로직이 실행되고 이에 따라 View가 바뀌는 방식이었다.

    • SwiftUI에서는 데이터의 변경에 따라 로직이 실행되고, 이에 따라 View가 바뀌는 방식이다.

 

MVVM for UIKit / SwiftUI

UIKit / SwiftUI에서 MVVM이 어떻게 구현되는지 개념적으로 간단히 살펴보자.

https://medium.com/ios-os-x-development/ios-architecture-patterns-ecba4c38de52

UIKit

  • ViewControllerView로써 취급된다.

  • ViewControllerUIView의 life-cycle을 관리하면서 ViewModel을 소유한다.

  • 'MVVM ViewViewModel간의 데이터 바인딩'은 ViewControllerViewModel간의 바인딩으로 구현된다.

    ViewController는 life-cycle의 책임만 맡게 하고 바인딩 자체는 UIViewViewModel이 직접 하도록 하는 방식의 바인딩도 존재할까?

  • 사용자 상호작용에 대한 처리는 ViewController에서 ViewModel의 특정 메서드를 호출하는 방식으로 구현 가능하다.(위에서도 말했지만 꼭 이렇게 할 필요는 없다)

     

SwiftUI

  • SwiftUI에서의 MVVM ViewView 프로토콜을 채택한 Struct가 맡는다.

  • View 프로토콜을 채택한 Struct들은 ViewModel을 소유한다.

  • ViewViewModel간의 데이터 바인딩은 Property Wrapper들을 통해 구현할 수 있다.(반드시 이렇게 할 필요 없음)

  • 사용자 상호작용에 대한 처리는 View에서 ViewModel의 특정 메서드를 호출하는 방식으로 구현 가능하다. (역시나 꼭 이렇게 할 필요 없음)

 

Event 처리와 데이터 바인딩

이 부분에 대해서는 딱히 이야기 할 수 있는 것이 없다. 왜냐하면 정해진 답이 없기 때문이다.

이벤트 처리

위에서 ViewViewModel 의 이벤트 처리 요구는 ViewModel의 메서드 호출로 구현이 가능하다고 했다. 하지만 이 또한 하나의 바인딩으로써 구현이 가능하다. (RxSwift같은 것 쓰는 경우)

데이터 바인딩

  • ViewViewModel 데이터 바인딩: View에서의 값 변화도 하나의 이벤트처럼 판단하고 위에서 말한 이벤트 처리 방식을 써볼 수 있다. SwiftUI를 쓰는 경우에는 Published 프로퍼티에 대한 $ 사용을 고려해볼 수 있다.

  • ViewViewModel 데이터 바인딩: 방법이 정말 많다. Delegate Pattern, Closure(콜백),KVO, NotificationCenter 등을 써볼 수 있으며 이것들을 Property Observer와 조합하여 사용해볼 수도 있다. (물론 Reactive 라이브러리 / 프레임워크도 사용해 볼 수 있다)

    다만, Reference Cycle이 생길 수 있으므로 ViewModelView를 Strong 하게 참조하도록 만들면 안되며 직접적으로 참조하도록 만드는 것보다는 의존성 역전 원칙 등을 이용해서 간접적으로 참조하게 만드는 것이 좋다.

 

데이터 바인딩에는 단방향 데이터 바인딩양방향 데이터 바인딩이 존재한다.
(개인적으로 구분해 보면 좋을 것 같아서 작성했을 뿐, iOS에서는 딱히 두 개를 구분하는 것 같지는 않다.)

  • 단방향: 데이터의 갱신 흐름이 단방향(1-way)인 것을 말한다.
    ex) 사용자에게 보여지는 read-only 레이블은 ViewModel에서 View로의 데이터 갱신만 이루어져도 된다.

  • 양방향: 데이터의 갱신 흐름이 양방향(2-way)인 것을 말한다.
    ex) 사용자가 전화번호를 입력할 때 숫자만 입력해도 중간에 - (하이픈)을 자동으로 삽입해주는 기능을 구현하는 경우
    → 입력하는 전화번호는 바로바로 ViewModel에 반영되야 하며, 적절한 상황 하에서 ViewModel이 데이터 중간에 하이픈을 삽입하면 해당 사항이 바로 View에도 반영되어야 한다.

 

Binding in SwiftUI

  1. View - ViewModel바인딩은 ObservableObject 프로토콜 및 Published같은 Property Wrapper를 주로 이용.

    ViewModelObservableObject를 채택하여 만들게 되며 이 ViewModelViewObservedObject로 소유하게 된다.(경우에 따라 EnvironmentObject, StateObject 등으로 소유하기도 한다) 이렇게 만들면 ViewModelView에 의해 Observed 되며 ViewModel@Published 프로퍼티에 변화가 생기면 해당 데이터 변화에 영향을 받는 View들이 다시 그려진다.

    • ViewModelView에 데이터 변경 알림을 보내는 방식에는 ObservableObjectobjectWillChange() 메서드가 관여
    • ObservableObject 프로토콜은 Combine 프레임워크의 프로토콜이며 바인딩에 쓰이는 여러 Property Wrapper들은 SwiftUI 프레임워크의 것들이다.
    • ViewViewModel 단방향 데이터 바인딩을 구현 하는 경우 View는 그냥 관찰중인 ViewModel@Published 프로퍼티를 쓰기만 하면 된다.
    • View↔︎ViewModel 양방향 데이터 바인딩을 구현 하는 경우에는 관찰중인 ViewModel@Published 프로퍼티를 쓸 때 $기호를 사용해야만 한다.
  2. Combine framework

    Apple이 제공하는 프레임워크이다. RxSwift처럼 쓸 수 있는 것 같은데, 잘 모르므로 일단은 패스..

     

Binding할 때의 주의점

  1. alpaca님은 블로그 글에서 '클로저를 통해 ViewModelView를 간접적으로 참조'하도록 만듦으로써 바인딩을 구현하셨다. 이처럼 바인딩 구현에 따라 간접적으로 ViewModelView를 알게 될 수도 있다. 이런 경우 Reference Cycle이 생길 수 있으므로 주의해야 한다.
  1. 많은 바인딩 코드는 boilerplate code-상용구-를 만들어내게 된다. 때문에 이에 대한 적절한 조치가 없는 경우 코드가 굉장히 복잡해질 수 있다.

 

MVVM을 사용함으로써 얻을 수 있는 이점

아래에 정리해놓은 이점들은 'iOS Architecture Patterns - Bohdan Orlov' 글을 참고하였다.

  1. Distribution(책임의 분배) - MVVM에서의 View는 바인딩을 통해 ViewModel로부터 보여줄 데이터를 가져온 뒤 직접 업데이트 한다.
    • MVC에서는 View가 스스로를 직접 업데이트하는 방식을 사용하지 않았었다. 대부분 ViewController가 그 역할을 대신 수행해주었다.(물론 Observer 패턴을 사용했던 전통적 방식의 MVC는 조금 달랐었을 수 있다)
      → 'MVC의 Controller에 비해 MVVM의 ViewModel이 수행해야 할 역할이 더 적다.'고 볼 수 있지 않을까?
  1. Testability(테스트의 용이성) - ViewModelView에 대해서 아무것도 모른다.(UIKit을 쓰는 경우 ViewController에 대해서도 모른다) 이것은 ViewModel을 쉽게 테스트할 수 있도록 만들어준다. View 또한 테스트가 가능하지만 UIKit에 종속적인 경우 건너뛸 수 있다고 한다.

  2. Easy of use(사용 편리성) - View를 수동으로 업데이트하는 것(MVP)보다 바인딩을 사용하는 경우 MVVM이 훨씬 간단하다.

    3번의 경우 논란의 여지가 있을 수 있다고 생각한다.

    • 일단 첫번째로, 바인딩을 구현하는 것이 간단한 것만은 아니기 때문이다. (바인딩이 구현되어있는 라이브러리/프레임워크를 사용하지 않는다면 상용구가 정말 많아진다)

    • 밑에서도 이야기 하겠지만, 작은 프로젝트의 경우 MVVM을 구현하는 것이 과할 수 있다.

    때문에 "MVVM이 MVC나 MVP보다 무조건 / 언제나 간단하다"고 볼 수는 없을 것 같다.

 

MVVM의 한계

MVVM의 한계점에 대해서도 간단히 살펴보도록 하자.

  1. 간단한 프로젝트를 하기에 MVVM은 과할 수 있다.
    → 바인딩같은 작업이 필요해서겠죠?

  2. 바인딩에 대한 툴이 없으면 많은 boilerplate(상용구) 코드가 발생할 수 있다.

  3. 큰 응용 프로그램에서 데이터 바인딩을 많이 쓰는 경우 많은 메모리를 쓰게 된다.
    위키백과에서 이렇게 말을 하고는 있는데 iOS도 그런가?

  4. Presentation Logic이 늘어나고 단일책임원칙(SRP)이 지켜지지 않는 경우 ViewModel 또한 비대해질 수 있다.
    → 근데 이건 어느 패턴이나 다 마찬가지라고 생각한다.

  5. 바인딩 등 여러가지 부분에 대해 정해진 답이 없다보니 사람마다 MVVM을 구현하는 방식이 다 다르다. 때문에 MVVM을 처음 접하는 입장에서는 패턴을 어떻게 구현해야 할지 막막하다.
    → 이것 저것 적용해보면서 본인만의 스타일을 만들어 나가야 한다. 🤣

 

MVC-MVP-MVVM 계보

탄생 배경에 대해서는 EEYatHo님의 글을 읽어보는 것이 좋다고도 서두에서 말했었다.

MVC


MVP

 

MVVM

SwiftUI에 꼭 MVVM을 쓸 필요는 없지만 둘은 찰떡궁합이다.

 
따지고보면 MVC, MVP, MVVM 모두 "View와 중간 매개체(Controller, Presenter, ViewModel)를 어떻게 구성시킬 것이냐"가 화두였던 것 같다. (Model은 웁니다 🤣)

그만큼 Presentation 부분에 대한 많은 고민들이 있었다는 것 아닐까?
(어떻게 구성하고, 연결지어야 '유지보수'나 '확장성', '재사용'등에 이점이 있을지)

내 생각일 뿐이지만,
MVC, MVP, MVVM 세가지 패턴은 View와 중간 매개체(Controller, Presenter, ViewModel) 사이에...

  • 뷰 설정 책임을 누가 가져갈 것이며
  • 누가 누굴 소유 할 것이고
  • 다른 객체를 어떻게 알고 있을 것인지

위의 세가지 부분에서 주요한 차이점이 존재하는 것 같다.

 

마지막으로

MVVM에서 ViewModel도 비대해질 수 있다고 위에서 이야기 했었다. 이에 대해 사람들은 Massive ViewModel이라고 부르기도 한다. 그러면 결국 또다른 패턴만이 해답인걸까? 나는 그렇게 생각하지 않는다.
MVC패턴에 관한 글에서 Massive ViewController에 대해 이야기 했던 것처럼 MVVM에서도 ViewModel을 적절히 분리하다보면 Massive ViewModel문제를 해결할 수 있지 않을까 생각한다.

"어떤 패턴이 좋은가?" 에 대해서는 아래와 같은 생각을 가지고 있다.

각자의 패턴이 장단점을 가지고 있는 것은 사실이지만 그것이 패턴간의 우위를 구분짓는데 사용될 수는 없다고 생각한다. 상황에 맞는 패턴을 적절히 선택하여 사용하는 것이 베스트 아닐까?

 

'어쨌든 MVC나 MVP의 중개자들(Controller, Presenter)과는 다르게 MVVM의 중개자 ViewModelView를 설정해주어야 하는 책임'으로부터 자유롭다..

이미지 원본 출처: 홍여랑님의 네이버 블로그

 

References

바인딩에 대해 많은 견해를 제공해주신 '내일날씨맑음''vivi' 감사합니다! 😊

profile
iOS 공부중인 Coden

21개의 댓글

comment-user-thumbnail
2021년 12월 20일

MVVM 외에도 많은 내용이 녹아들어있네요. 좋은 정리 감사합니다. 많은 공부가 되었습니다!
근데 SwiftUI에서 enum이 View가 될 수는 없나요?

1개의 답글
comment-user-thumbnail
2021년 12월 20일

MVVM 에서 양방향 바인딩이 가능하다고 작성해주셨는데, 양방향 바인딩의 예가 어떤 것이 있을까요?

1개의 답글
comment-user-thumbnail
2022년 4월 5일

와! 좋은글 감사합니다 ^^ 클린아키텍처도 포스팅해주시면 정말 감사할 것 같습니다👍

답글 달기
comment-user-thumbnail
2022년 7월 4일

와! 좋은글 감사합니다 ^^ 클린아키텍처도 포스팅해주시면 정말 감.사.할.것.같.습.니.다.👍

답글 달기
comment-user-thumbnail
2022년 7월 8일

좋은 글 감사합니다!!

답글 달기
comment-user-thumbnail
2023년 2월 20일

I do believe alll the ideas you have presented in your post.
They're very convincing and can definiely work. Nonetheless, the
posts are very brief for novices. May you please prolong them a bit from subsequent time?
Thank you for the post.
https://www.rndinfoserve.com/

답글 달기
comment-user-thumbnail
2023년 7월 3일

I’m a super hot, independent girl with a desirable figure that everyone adores, a seductive face, and a cunning, horny mind. You’ll be led into a paradise by my sinful thoughts, and you won’t want to leave. With my sexy call girl services cash on delivery, I can give you the passionate night of your dreams.
https://nidhipradhan.com/
https://www.escortserviceudaipur.in/

답글 달기
comment-user-thumbnail
2023년 10월 14일

If you’ve ever bought something an influencer recommended online, you’ve likely come across an affiliate marketing business. Online creators often build partnerships with brands to promote its https://sites.google.com/view/affiliateservices/home products and services. In return, they earn a commission for each sale.

답글 달기
comment-user-thumbnail
2023년 10월 19일

We are hub of range of escorts picked from distinct areas of the nation as well as abroad. We are very well versed with the spice of variety that every men of this world likes to have and to not to disappoint you, we bring you happening and kinky Delhi Escorts from North Indian states like Himachal, Kashmir, Punjab, Haryana and Uttar Pradesh.
https://twikkers.nl/blogs/152992/How-To-Book-Escort-In-Delhi
https://travelwithme.social/read-blog/18744_are-escort-in-delhi-24-7-available.html
https://jpst.it/3nZkp
https://penzu.com/p/c573d81b
https://indianapolis.adposta.com/how-to-get-escort-in-delhi-815694
https://vherso.com/read-blog/114854_where-to-find-escorts-agency-in-delhi聽.html
https://ekcochat.com/read-blog/60528_where-to-find-high-class-model-escorts-in-delhi.html
https://huduma.social/blogs/271683/Delhi-Call-Girls-100-Real-Photo-s-of-Call-Girl
https://www.tamaiaz.com/blogs/130831/Delhi-Call-Girls-4-9k-With-COD-Free-Home-Delivery
https://tannda.net/read-blog/36219_call-girls-in-delhi-with-hotel-room-just-start-9999.html
https://ouptel.com/read-blog/22203
https://web.doopinet.com/read-blog/2145_delhi-call-girls-100-real-photo-039-s-of-call-girl-in-delhi.html
http://www.mizmiz.de/read-blog/9314_delhi-call-girls-free-delivery-24x7-at-your-doorstep.html
https://justproms.com/read-blog/58987_delhi-call-girls-4-9k-with-cod-free-home-delivery-service.html
https://www.diccut.com/read-blog/9422_where-to-find-high-class-model-escorts-in-delhi.html
https://polkasocial.org/read-blog/8914_book-call-girls-in-delhi-3000-with-free-24x7-hotel-delivery.html
https://say.la/read-blog/11741_whatsapp-24-7-to-book-sassy-call-girls-in-delhi.html
https://www.find-topdeals.com/blogs/69972/Delhi-Call-Girls-5000-Cash-Payment-Free-Home-Delivery
https://nyasowi.com/read-blog/7243_delhi-call-girls-free-delivery-24x7-at-your-doorstep.html
http://bedfordfalls.live/read-blog/63474_delhi-call-girls-high-profile-model-escorts-100-verified.html

답글 달기
comment-user-thumbnail
2023년 11월 1일

My name is Chavi Goyal and I am a 22 year old independent escort in Pune. I'm the one you're looking to enjoy a great moment without rushing, you'll love to meet me. I am very naughty and daring in bed; My skills will drive you crazy. In bed I am very friendly and lively, I am ready to give you the best night of your life.
https://www.chavigoel.com/

답글 달기