티스토리 뷰

TIL

[TIL] 2022 / 08 / 31

희철 2022. 8. 31. 18:24

MVC와 MVVM은 상위호환적인 개념이 아님.

 

 

MVC

 

 

Model - View - Controller로 이루어진 아키텍쳐

 

앱의 한 부분을 제어하기 위해 MVC패턴 하나가 사용되는 것

-> Scene이 여러 개가 있고 각각을 담당하는 뷰컨트롤러와 모델이 있다면 MVC패턴도 뷰컨트롤러 수만큼 있는 것.

 

 

Model

-> 화면과 상관 없이, 본질적인 데이터만 담당

-> 네트워킹을 통해 데이터를 받아올때 만들어줬던 구조체같은거 생각하면 될 듯.

-> 모든 의사소통은 컨트롤러를 통해 전달

-> 뷰와 연관되어 있지 않음.

 

Controller

-> Model이 화면에 어떻게 표시될지 정해주는 역할. 보통 UI로직이 들어감.

-> 항상 접근이 가능하고 Model에 대한 모든 것을 알고있음.

 

View

-> Label, Button같이 컨트롤러가 화면에 보여주기 위해 사용하는 요소.

-> 뷰는 자기가 어디에 속해있는지를 알 수 없기때문에 Outlet같은 방식으로 속한 컨트롤러와 소통

-> 뷰는 모델에 영향을 줄 수도 있기 때문에, 터치 이상으로 복잡한 소통을 하는 경우엔 Delegate, DataSource와 같은 프로토콜을 이용해 컨트롤러에게 책임을 위임함.

 

 

단점

 

컨트롤러가 하는 일이 너무 많음.

-> 모델과 뷰가 컨트롤러에 의존을 하고 있기 때문에

 

 

MVVM

 

 

 

Model - View - ViewModel

 

뷰와 모델을 명확하게 분리하는 것이 목적

->  여기서 뷰는 UI와 관련된 코드를 의미(뷰컨트롤러)

 

모델의 모든 변화를 뷰가 파악하고 UI를 업데이트 할 수 있어야함.

 

MVC와 비교하면 컨트롤러 대신 로직들을 ViewModel에서 관리하고, 뷰컨트롤러는 뷰로 취급됨.

 

 

Model

-> 뷰와 독립적. UI 관련 프레임워크를 import하지 않아야함.

-> 모델이 바뀌었을때, 뷰모델에게 사실을 알려줌.

 

View

-> MVC에서의 뷰컨트롤러 역할.

-> 즉, 모든 비즈니스 로직을 담당.

-> 뷰모델을 참조함.

-> 뷰에서는 상태같은 것은 받지 않기 때문에 모델에 바로 전달할 수 없음. 그래서 뷰모델을 통해서 전달

-> 데이터 바인딩 작업이 양방향으로 이루어짐.

*양방향 데이터 바인딩이 가능하려면 didSet, Closure, Delegate, Notification 등으로 구조를 만들어야함.

-> 코드베이스로 구성할때 따로 View클래스를 만들어주더라도 어차피 뷰에서 담당하게됨.(뷰컨트롤러)

    단지, 가독성을 위해서 쪼개는 것임.

 

ViewModel

-> UI와 비즈니스 로직을 분리하기 위해 사용.

-> Model참조. 

-> 뷰로부터 변경 사항을 받아 Model을 업데이트하고, 이를 View에 반영시킴

-> Interpreter의 역할

-> 뷰에 변경 사항을 직접 알리지 않고, 변경 되었다는 사실만 알려줌. 

-> 기존에 뷰컨트롤러에서 했던 일부 기능을 받아온 것(조건 판단이나 dateFormatter같이 눈에 보이진 않는 로직)

 

 

 

MVVM 아키텍쳐를 적용해본 코드

 

 

Observable 클래스를 이용하여 양방향 데이터 바인딩이 가능하도록 해주었음.

-> 즉, 모델과 뷰에서 서로 바뀌는 것들을 알려주는 것이라고 생각.

 

위의 코드를 한 단계씩 진행하며 이해해보겠음.

 

1. 뷰컨트롤러에서 PersonViewModel 인스턴스가 viewModel로 선언되었음.

 

-> list가 이니셜라이징된 것. 그래서 viewModel.list는 이제 page, totalPage, totalresults, results를 0, 0, 0, []의 값으로 갖고 있을거임.

 

2. viewDidLoad에서 fetchPerson메서드 실행

 

PersonViewModel 클래스에서 보면 가장 먼저 "fetchPerson"이 출력될거고, list.value의 값이 출력된 뒤에 네트워킹이 진행될거임.

 

3. fetchPerson코드 다음으로 bind메서드 실행

 

이때 fetchPerson의 네트워킹은 아직 진행중인 상태이므로 아직까지 "처음 리스트"까지만 출력된 상태

 

그래서 바로 "bind"가 출력되고 메서드를 실행.

 

bind를 출력했으면 closure(value)를 실행해야됨.

 

여기서 closure는 bind메서드의 매개변수임.(탈출 클로저)

 

즉, 아래 코드의 클로저 부분을 의미하는 것. person에는 value가 들어가는 것.

근데 이전에 list를 선언할 때의 초기값이 value에 들어있을 것임.

 

그래서 clousre(value)이 실행되면 두 출력구문이 실행되고 tableView가 리로드 될 것임.

 

다음으로, listener에 closure를 넣어줌.

-> 위 코드에 보이는 클로저가 listener에 저장되게됨. 즉, listener는 테이블뷰를 리로드하는거임.

결론적으로 bind메서드의 목적은 didSet에서 tableView.reloadData()코드를 실행할 수 있게 하는 것.

 

4. 네트워킹이 끝나고 person값을 받아와서 list.value에 넣어줌.

 

원래 value안에는 초기값이 저장되어 있었음.

 

근데 받아온 person데이터를 넣게 되면 데이터가 바뀌기 때문에 didSet구문이 실행될 것임.

 

그러면 listener가 value라는 값을 받아 클로저를 실행할 것임.

 

이제 다시 person과 viewcontroller bind가 출력이 될 텐데, 이땐 person에는 초기값이 아닌 네트워크 통신을 통해 받아온 값이 들어가있을 것임.

 

 

 

너무 어렵다.

 

코드에 많이 적용해봐야할듯.

 

위의 코드에서 확인해 볼 수 있는 것은 아래와 같다.

 

- Observable 클래스를 이용해 양방향 데이터 바인딩이 가능하도록 구성.

- 뷰모델에서 로직 실행

'TIL' 카테고리의 다른 글

[TIL] 2022 / 09 / 05  (0) 2022.09.05
[TIL] 2022 / 09 / 02 (GCD)  (0) 2022.09.02
[TIL] 2022 / 08 / 29  (0) 2022.08.29
[TIL] 2022 / 08 / 27  (0) 2022.08.28
[TIL] 2022 / 08 / 25  (0) 2022.08.26
댓글
최근에 올라온 글
Total
Today
Yesterday