MVVM in iOS

  1. MVVM 패턴
    1. https://www.raywenderlich.com/34-design-patterns-by-tutorials-mvvm 에 따르면
      1. Massive View Controller 때문에
      2. Model을 View에 보여줄 값으로 바꾸는 ViewModel을 도입한다
      3. ViewModel을 각기 View의 property에 주입하는 코드를 ViewModel로 옮길 걸 추천한다. 하지만 이는 ViewModel이 한 View에만 적용될 때고
      4. 여러 View에 사용된다면 configure하는 코드를 View에 넣을 것을 추천한다
      5. 아니 그러면 ViewModel이 View를 알게 되는 것/ View가 ViewModel을 알게 되는 것으로 나뉘어버린다.
      6. 구조가 확 갈린다고 볼 수 있다.
      7. 그리고 ViewModel은 Model을 소유한다. Controller는 View와 ViewModel을 소유한다.
      8. 또다른 coupling이 생기는 것은 원치 않기 때문에 나는 ViewController가 ViewModel의 값을 View에 configure하는 게 좋다고 생각한다.
      9. 그럼 이런 형식으로 보여주는 tutorial이 있나?
      10. https://youtu.be/bFoLlwuzAtk
      11. 여기에서는 그렇다! 
      12. ViewController를 생성할 때 아예 model을 이용한 viewModel을 넣어줌
      13. 그걸로 View를 보여준다.
      14. ViewController가 property로 model을 갖고 있던 것이 viewModel로 대체된다
      15. 여기서 피어난 궁금증은 그럼 유저 액션이 있을 때는 어떻게 되냐는 거다.
      16. ViewModel에 알려주고, 새로워진 값을 View에 업데이트를 한다면. 이것 역시 똑같이 Controller에서 하는 것이 되겠다.
      17. 근데 MVVM은 항상 binding하는 개념을 끌고 온다. 위의 과정이 보통 그런식으로 수행된다. Reactive나 Combine으로
      18. 왜 그런거지?
        1. https://en.wikipedia.org/wiki/Model–view–viewmodel
        2. MVVM 개념을 보면 알 수 있다.
        3. MVVM 자체의 목적은 Presentation Logic을 (Business Logic과 Data)에서 분리하기 위함이다. 
        4. ViewModel은 Display Logic을 위한 것이다
        5. 마틴 파울러의 Presentation Model Design Pattern의 변형이다
          1. https://martinfowler.com/eaaDev/PresentationModel.html  Represent the state and behavior of the presentation independently of the GUI controls used in the interface
          2. 인터페이스의 GUI 컨트롤에서 presentation의 상태와 행동을 독립적으로 분리하여 표현하는 것. 
        6. 특히 event-driven programming에 특화되어 있다
        7. model-view-binder라고 말하기도 한다
        8. Components
          1. View
            1. Event handling을 data binding(property나 event callback 등)을 통해서 ViewModel에 전달한다
          2. View Model
            1. Public property와 command를 가진 View의 추상
            2. MVC의 Controller나 MVP의 Presenter 대신에 Binder가 view와 view model의 bind된 properties 사이의 커뮤니케이션을 한다
            3. Model의 State
            4. Presenter와 Binder의 차이는 Presenter는 view에 대한 reference가 있다면 binder은 없다.
            5. 대신에 view가 직접적으로 view model의 property와 bind된다. update를 보내고 받기 위해서. 
              1. reference를 통한 update가 아니라 bind!
            6. 효과적으로 동작하려면 binding 기술이 있던 bind를 위한 boilerplate 코드가 있던 해야 함
          3. Binder
            1. View와 ViewModel을 연결한다
            2. binding 기술이 이 패턴을 가능하게 한다. binder가 없다면 MVC나 MVP를 boilerplate 코드와 함께 쓰는 것과 다름없다. 
        9. Rationals
          1. View Code에서 GUI(User Interface, 유저와의 상호작용 코드)를 없애는 것에 있다.
          2. 그래서 UX 개발자는 GUI 코드를 작성하는 게 아니라 application 개발자가 작성한 view model에 binding만 한다.
          3. 비즈니스 로직은 모두 View Layer에서 빠진다.
          4. 이로써 interactive 디자이너들은 programming이나 비즈니스 로직이 아닌 UX에만 집중할 수 있다
          5. 결과적으로 binding을 사용하므로서 code-behind가 아닌 model과 framework가 최대한 많은 operation을 수행한다. view를 직접적으로 manipulate하는 application logic을 없애거나 최소화한다.
      19. 왜냐하면 MVVM은 그 패턴 자체가 Model과 ViewModel을 자동적으로 binding하는 걸 특징으로 하기 때문이다. 그래서 유저 이벤트를 viewModel에 알려주면 ViewModel이 자동적으로 View를 업데이트해야한다. 
      20. 그러려면 View가 ViewModel을 갖고 있으면서 이벤트를 전달하고, 이를 ViewModel이 처리해서 View에 알려주면, ViewModel의 property에 직접 binding된 View의 요소들이 업데이트되면 된다.
      21. View가 ViewModel을 갖고 있는 것이 좋아 보임. 
  2. 그럼 Combine은? https://developer.apple.com/documentation/combine/receiving-and-handling-events-with-combine 
    1. iOS 13+
    1. 컴바인은 이벤트 처리를 위한 프레임웍이다
    2. delegate이나 completion handler 없이 이벤트 소스에 하나의 processing chain을 달 수 있다
let sub = NotificationCenter.default
    .publisher(for: NSControl.textDidChangeNotification, object: filterField)
    .map( { ($0.object as! NSTextField).stringValue } )
    .assign(to: \MyViewModel.filterString, on: myViewModel)
  1. 애플 문서에 ViewModel이 등장한다. MVVM의 Binding 기술이 Combine이다.
  2. SwiftUI tutorial에 MVVM 구조가 나오진 않는다. View가 직접 model의 리스트(modelData)를 갖고 있고
    1. 유저 이벤트가 발생하면
    2. model의 값을 직접 변경한다
    3. 사실 이 model의 리스트를 ViewModel이라고 보면 된다.
    4. 이 안의 property가 Published이다.
    5. view가 modelData에 user action을 전달하면 값이 변경되고 다양한 view가 Combine을 통해 modelData에 bind되어 있기 때문에 별다른 코드가 필요 없이 변경된 값이 바로 반영이 된다.
  3. 결국 ViewModel이 View를 Configure하는 것이 아니라, View가 ViewModel을 소유하고 ViewModel 값에 스스로 구독한다. 위에서 고민했던 view와 viewmodel의 configure의 위치가 SwiftUI로의 확장까지 고민한다면 View에 위치하는 것이 맞아보인다. 결국 Controller는 사라질 것이므로.
    1. binding은 View에 존재하고(ViewModel에의 연결)
      1. 즉, ViewModel은 View를 모른다
    2. display logic, presentation logic은 ViewModel에 위치시킨다
    3. 내 나름의 MVVM Design Pattern의 적용을 그려본다면(화살표는 “안다”라는 의존성을 의미함)

요약하자면 MVVM의 핵심은

  1. ViewController의 역할을 줄인다.
    1. Presentation Logic은 ViewModel이 수행한다.
  2. View Layer에서 GUI Code, 비즈니스 로직을 제거한다.
    1. 뭔가가 뒤에서 View를 변경하거나 하지 않는다. 투명하게 View는 그냥 ViewModel에 Bind된다.
    2. ViewModel은 View를 모르고, View의 추상으로서 존재한다. 그래서 View Layer는 View의 추상에 구독만 하니까 Business Logic에서 철저히 분리되고. ViewModel은 View가 아닌 View의 추상에만 의존하게 된다.(의존이라기 보다도 자기 자신이 그 추상 그자체임). 그래서 View의 세부 구현이나 변경에서는 분리되게 된다.

MVVM 이해하기

  1. https://www.raywenderlich.com/34-design-patterns-by-tutorials-mvvm
  2. Coordinator Pattern과 마찬가지로 Massive ViewController의 문제를 해결하기 위함
  3. ViewController에서 Model을 View에 보여주기 위해 변경하는 코드들을 분리함
  4. ViewController는 여전히 존재하지만 ViewModel이 메인이다
  5. ViewModel: Model을 View에 보여주기 위해 적절한 값으로 변경해줌
  6. ViewController가 ViewModel, View를 소유하고
  7. ViewModel이 Model을 소유한다.
  8. ViewModel이 View를 사용한다. (ViewModel은 View를 안 다)

그럼 뭔가를 보여줄 일이 생긴다면

  1. ViewController를 생성할 때 아예 model을 이용한 viewModel을 넣어줌
  2. 그걸로 View를 보여준다.
  3. ViewController가 property로 model을 갖고 있던 것이 viewModel로 대체된다

유저 액션이 발생했다면?

  1. 유저 액션이 일어났음을 뷰 컨트롤러가 감지함
  2. ViewModel에 알려주면
  3. ViewModel이 액션에 맞게 모델 값을 바꾼다
  4. 이를 View에 적용하는 코드는 Controller에서 함/ ViewModel에서 할 수도. 뭐가 맞는 걸까?
    1. https://www.raywenderlich.com/34-design-patterns-by-tutorials-mvvm 에서는 view에 세팅하는 코드를 viewModel에 넣음
    2. 아래 영상에서는 View Controller에서 하고 있다
    3. ViewController는 View를 소유할 수 밖에 없음. ViewModel이 View를 알게 하기 보다는 transformation에 관련된 일만 ViewModel에서 하고 View를 제대로 알고 주입하는건 Controller에서 하는 게 낫지 않을까?
    4. SwiftUI에서는 어떻게 되지?
  1. Model: Data+ Logic
  2. View: Declared. Time independent <-> Imperative. 시간이라는 축이 있음. 언제든 펑션을 불러서 뷰를 바꿀 수 있음
    1. struct는 read-only다 누구도 바꿀 수 없다. 그래서. 너가 선언한대로만 보여질 거다
    2. Stateless
    3. Reactive: to model
    4. Automatically observes publications, pulls data and rebuilds
  3. ViewModel
    1. Bind views to model
      1. Automatic update
    2. Notices changes in model
    3. Interpreter(model(복잡할 수 있다) -> view)
    4. Publishes something changes
    5. Processes Intent(User)
  4. 결론적으로 SwiftUI에서는 주입하는건 observing으로 자동으로 되어버린다(이런 observing, publishing을 하게 해주는게 Combine)
  5. View가 ViewModel을 소유해버림

리액티브한 ViewModel을

  1. Input
  2. Output
  3. Input을 output으로 변경하는 transform 함수로 구성할 수 있다

결론

MVVM은 결국 MVC와 다른건 뷰컨트롤러에서 모델을 직접 접근해서 많은 일들을 처리했다면 그런 로직들을뷰모델에 옮긴다는데에 의미가 있는 것 같다. 사용자 인터페이스(뷰)의 개발을 비즈니스 로직 또는 백-엔드 로직(모델)로부터 분리시켜서 뷰가 어느 특정한 모델 플랫폼에 종속되지 않도록 해준다. 결국 MVC와의 차이는 “Presentation 로직”을 ViewController 코드에서 ViewModel 코드로 옮긴다는데에 있다.

Coordinator Pattern 이해하기

  1. https://www.hackingwithswift.com/articles/71/how-to-use-the-coordinator-pattern-in-ios-apps
  2. Massive View Controller에서 Navigation(화면 전환)과 관련된 코드를 분리하기 위함
  3. A → B 화면으로 navigate할 때 A가 B를 생성하므로 강한 coupling이 있다
  4. A,C,D 화면에서 모두 B화면으로 navigate을 한다면 이를 재활용해서 코드 중복을 제거할 수 있다
  5. Main 들어오는 것부터 coordinator로 관리

The role of model in MVC architecture in iOS

MVC: https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html#//apple_ref/doc/uid/TP40008195-CH32-SW1

Model Object:

https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/ModelObject.html#//apple_ref/doc/uid/TP40008195-CH31-SW2

model object is a type of object that contains the data of an application, provides access to that data, and implements logic to manipulate the data.

https://ko.wikipedia.org/wiki/모델-뷰-컨트롤러

In the picture in the page above, the connection to database is to Model, not Controller.

 

https://developer.apple.com/swift/blog/?id=37

In the code of the post above, the network call method is in model object extension.

iOS Design Patterns

  1. MVC
    1. Model and View do not know each other.
  2. MVVM
    1. Separates transformation of model to be shown in view from view controller to ViewModel
    2. ViewController owns viewmodel
    3. https://www.raywenderlich.com/34-design-patterns-by-tutorials-mvvm
  3. MVVM-C
    1. Coordinator has presentation logic from view controllers
    2. https://junhyi-park.medium.com/mvvm-c-학습자료-정리-7f169f3e376a
  4. MVP
    1. Separates all logics except for view related part from view controller to Presenter
    2. UIViewController is View Part.
    3. P is Presenter. It
    4. ViewController owns presenter.

Medium.com에서 보기