죄송합니다. 저도 정리하는데 깔금하게 이해가 안됩니다. 깔금하게 이해 되면 다시 올리겠습니다.
MVC과 MVVM 패턴이란?
MVC 패턴
모델은 앱에서 사용되는 데이터를 저장하고, 처리하는 부분입니다. 뷰는 사용자에게 보여지는 ui부분입니다. 컨트롤러는 사용자의 입력을 받고 처리하는 부분입니다.
MVC 패턴의 동작은 일단 액션이 들어오고 컨트롤러에서 액션을 확인합니다, 그리고 액션에 대해 모델을 업데이트 합니다. 컨트롤러를 통해 모델을 나타내줄 뷰를 선택합니다. 그후 뷰는 모델을 이용해 화면을 나타냅니다.
MVC에서 뷰가 업데이트 되는 방법은 크게 3가지가 있는것 같습니다. 뷰가 모델을 이용해 직접 업데이트 하는 방법. 모델에서 뷰에게 알림(notify)을 통해 업데이트 하는 방법, 뷰가 폴링으로 주기적으로 모델의 변경을 감지해 스스로 업데이트 하는 방법.
음근데 notify가 nsnotification을 이용한다는거 같은데, 어케하는건지 잘 모르겠다.....
Controller는 여러개의 View를 선택할 수 있는 1:n 구조입니다.
Controller는 View를 선택할 뿐 직접 업데이트 하지 않습니다. (View는 Controller를 알지 못합니다).
그래서 뷰의 변화를 컨트롤러에 직접 전달하지 않습니다. 대신에 delegate 또는 data source를 이용해 해결합니다. 사용자가 화면에 입력이나 변화 이벤트를 주면 해야할 일을 뷰컨에 위임합니다. 따라서 뷰의 변화에 대한 로직은 뷰컨에 존재합니다.
MVC 패턴의 단점은 View와 Model 사이의 의존성이 높다는 것입니다. View와 Model의 높은 의존성은 어플리케이션이 커질 수록 복잡하지고 유지보수가 어렵게 만들 수 있습니다. 이 부분도 어떤 의미에서 복잡해 진다는건지 모르겠다......
[https://medium.com/ios-development-with-swift/mvc-%ED%8C%A8%ED%84%B4-in-ios-7751911f8ca8] 여기서 추가적인 설명을 아래더 이어나가겠습니다. 패턴에 대한 얘기는 정말 긴듯...
그러나 iOS의 MVC는 Model-View-Controller의 분리가 완전하지 않아서 실제로는 View의 생명주기에 관한 코드가 Controller에 모두 위치하고 네트워크 통신에 관한 코드도 Controller에 위치하게 되기 때문에 Controller의 크기가 지나치게 커지는 경향이 있습니다. 이런 문제점을 극복하고자 MVC-N, MVP, MVVM 등등의 패턴들을 사용하기도 합니다.
제 경우에도 네트워크 통신에 관한 코드가 컨트롤러에 위치하여, 컨트롤러의 소멸후에 네트워크 통신이 완료되면 컨틀로러에서의 뷰의 갱신이 어려웠습니다. 그래서 모델에서 하는 쪽으로 수정하였습니다.
MVVM 패턴은 Command 패턴과 Data Binding 두 가지 패턴을 사용하여 구현되었습니다. Command 패턴과 Data Binding을 이용하여 View와 View Model 사이의 의존성을 없앴습니다. View Model과 View는 1:n 관계입니다.
이제 이 블로그의 MVVM 패턴에 대한 얘기입니다. [https://ehdrjsdlzzzz.github.io/2019/02/17/MVVM-in-iOS/]
MVVM 패턴의 이면에 존재하는 아이디어는 화면의 각 뷰에 대한 데이터를 나타내는 뷰 모델(View Model)이 각 뷰(View)를 지원한다는 것이다. 이는 만일 우리가 뉴스 어플리케이션을 만든다면 뷰 뉴스 아이템을 보여주는 UITableView로 구성되어 있을 것이고 뷰 모델은 제목, 설명, 출간 날짜, 저자 그리고 출처 등과 같이 뉴스를 표현해주는 데이터로 이루어져 있을 것이다.
매핑 작업이 끝나면 뷰 모델을 할당하고 이는 테이블 뷰의 리로드로 이어진다. 이 작업은 프로퍼티의 didSet 행위에 의해 자동으로 이루어진다. didSet 행위는 클래스의 생성자 내부에서 일어나는 할당에는 실행되지 않는다는 것을 명심하자.
struct ArticleListViewModel {
var title: String? = "Articles"
var articles: [ArticleViewModel] = []
}
extension ArticleListViewModel {
init(articles: [ArticleViewModel]) {
self.articles = articles
}
func loadArticles(callback: (([Article] -> Void)) {
URLSession.shared.dataTask(with: url) { data, response, error in
if let data = data {
let json = try! JSONSerialization.jsonObject(with: data, options: [])
articles = articleDictionaries.flatMap { Article(dictionary: $0) }
}
DispatchQueue.main.async {
callback(articles)
}
}.resume()
}
}
private var viewModel: ArticleListViewModel = ArticleListViewModel() {
didSet {
self.tableView.reloadData()
}
}
이때 didSet은 viewModel이 바뀌어야 발동합니다. 인스턴스의 프로퍼티가 바뀌어 봤자 안됩니다.
몇몇의 독자들이 뷰 모델은 네트워킹 코드나 데이터 접근 코드를 포함해선 안된다에 대해 지적을 해주었다. 심지어 iOS 커뮤니티에서도 각자 다른 취향의 MVVM을 사용하는 개발자들을 보았다. 각자의 상황에 맞게 MVVM 아키텍처를 선택해서 사용하면 될 것 같다. 글에서 이 대목을 보면 뷰모델에 네트워킹 코드가 들어가기도 하고 아니면 다른 클래스에 빼서 네트워킹은 따로 처리하기도 하는것 같습니다.
Data Binding
[https://wnstkdyu.github.io/2018/04/20/mvvmdesignpattern/]
데이터 바인딩의 개념은 쉽게 말해 Model과 UI 요소 간의 싱크를 맞춰주는 것이라 할 수 있다(정확히 말하면 UI 데이터 바인딩이지만 iOS를 다루기 때문에 이것을 다룬다). 이 패턴을 통해 View와 로직이 분리되어 있어도 한 쪽이 바뀌면 다른 쪽도 업데이트가 이루어져 데이터의 일관성을 유지할 수 있다.
iOS에서 데이터 바인딩을 하는 방법은 다음과 같다.
- KVO
- Delegation
- Functional Reactive Programming
- Property Observer
swift 기준으로 다시 쉽게 써보았습니다.
https://pinelover.tistory.com/313
'취업,면접 대비 > cs 전공 공부' 카테고리의 다른 글
<함수 호출과 메모리> (0) | 2020.03.21 |
---|---|
<객체지향> 인스턴스 맴버, 클래스 맴버, 스태틱 맴버란? (0) | 2020.03.16 |
<객체 지향> public 과 private (0) | 2020.03.13 |
RestAPI란? (0) | 2020.03.11 |
url 규칙 (0) | 2020.03.11 |